<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Ein swap Problem wegen Konstanten]]></title><description><![CDATA[<p>Hallo zusammen,</p>
<p>Zuerst den Aufbau, ich hoffe ich konnte ihn genug kürzen:</p>
<pre><code class="language-cpp">class BasicNode
{
  Element* const m_parent;
  Document* const m_document;

  // Werden beide bei der Erstellung des Objektes gesetzt,
  // werden aber nicht kopiert oder geswapt.
};

// Ein paar Nodes:
class Element : public BasicNode
{ }

class Comment : public BasicNode
{ }

// usw.

// Ein etwas spezieller Wrapper:
class NodeWrapper
{
public:
  typedef boost::variant&lt;Comment*, Element*, ...&gt; Node;

private:
  Node m_node;

public:
  // Konstruktoren und Methoden ...
  // Swap wäre möglich, aber leicht unsinnig.
};

// Zur eigentlichen Problemstelle
class NodeContainer
{
private:
  typedef std::vector&lt;NodeWrapper&gt; Container;

public:
  typedef Container::const_iterator ConstIterator;
  // ...

private:
  Element* m_parentForNewNodes;
  Document* m_documentForNewNodes;

  Container m_container;

  // ...
public:
  template&lt;typename NodeT&gt;
  NodeT&amp; push_back(NodeT const&amp; node)
  {
    NodeT* newNode = new NodeT(node, m_parentForNewNodes, m_documentForNewNodes);
    // Die letzten beiden Parameter gehen dann weiter zur BasicNode.

    m_container.push_back(NodeWrapper(newNode));

    return *newNode;
  }

  // ...

  void swap(NodeContainer&amp; nodeContainer)
  {
    // WIE? Siehe dazu Text unten, falls das Problem noch nicht klar ist.
  }
};
</code></pre>
<p>Das Problem bei diesem swap ist ja, dass ich nicht einfach den Vektor swappen kann. Das würde zwar am schnellsten gehen, aber die darin gespeicherten Zeiger, weisen dann auf Nodes mit den falschen Angaben zu <code>m_parent</code> und <code>m_document</code> in BasicNode.<br />
Ich muss also diese konstanten Zeiger verändern. Gut, dann mache ich sie halb nicht mehr konstant, das ist das kleinste Problem. Das grössere ist, dass ich eine öffentliche Methode anbieten müsste, um diese Zeiger zu verändern.<br />
Dies würde aber bedeuten, dass man von ausserhalb der Bibliothek diese Werte verändern kann, was aber nur dazu führt, dass Fehler erzeugt werden. Die Werte dürfen nicht von ausserhalb geändert werden!<br />
Was kommt also als nächstes in Frage? Friend, also dass BasicNode sich als friend von NodeContainer deklariert. So könnte ich eine private Methode in BasicNode anbieten, welche NodeContainer bedienen kann. Aber so richtig schön, finde ich diese Lösung nicht. Ich habe noch nie friend verwendet, bisher war es nie nötig, es gab immer einen anderen Weg. Aber hier sehe ich einfach keinen ...</p>
<p>Aber vielleicht könnt ihr mir weiterhelfen ... <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f642.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--slightly_smiling_face"
      title=":)"
      alt="🙂"
    /></p>
<p>Grüssli</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/227004/ein-swap-problem-wegen-konstanten</link><generator>RSS for Node</generator><lastBuildDate>Wed, 30 Sep 2026 06:22:01 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/227004.rss" rel="self" type="application/rss+xml"/><pubDate>Sun, 09 Nov 2008 14:41:55 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Ein swap Problem wegen Konstanten on Sun, 09 Nov 2008 14:41:55 GMT]]></title><description><![CDATA[<p>Hallo zusammen,</p>
<p>Zuerst den Aufbau, ich hoffe ich konnte ihn genug kürzen:</p>
<pre><code class="language-cpp">class BasicNode
{
  Element* const m_parent;
  Document* const m_document;

  // Werden beide bei der Erstellung des Objektes gesetzt,
  // werden aber nicht kopiert oder geswapt.
};

// Ein paar Nodes:
class Element : public BasicNode
{ }

class Comment : public BasicNode
{ }

// usw.

// Ein etwas spezieller Wrapper:
class NodeWrapper
{
public:
  typedef boost::variant&lt;Comment*, Element*, ...&gt; Node;

private:
  Node m_node;

public:
  // Konstruktoren und Methoden ...
  // Swap wäre möglich, aber leicht unsinnig.
};

// Zur eigentlichen Problemstelle
class NodeContainer
{
private:
  typedef std::vector&lt;NodeWrapper&gt; Container;

public:
  typedef Container::const_iterator ConstIterator;
  // ...

private:
  Element* m_parentForNewNodes;
  Document* m_documentForNewNodes;

  Container m_container;

  // ...
public:
  template&lt;typename NodeT&gt;
  NodeT&amp; push_back(NodeT const&amp; node)
  {
    NodeT* newNode = new NodeT(node, m_parentForNewNodes, m_documentForNewNodes);
    // Die letzten beiden Parameter gehen dann weiter zur BasicNode.

    m_container.push_back(NodeWrapper(newNode));

    return *newNode;
  }

  // ...

  void swap(NodeContainer&amp; nodeContainer)
  {
    // WIE? Siehe dazu Text unten, falls das Problem noch nicht klar ist.
  }
};
</code></pre>
<p>Das Problem bei diesem swap ist ja, dass ich nicht einfach den Vektor swappen kann. Das würde zwar am schnellsten gehen, aber die darin gespeicherten Zeiger, weisen dann auf Nodes mit den falschen Angaben zu <code>m_parent</code> und <code>m_document</code> in BasicNode.<br />
Ich muss also diese konstanten Zeiger verändern. Gut, dann mache ich sie halb nicht mehr konstant, das ist das kleinste Problem. Das grössere ist, dass ich eine öffentliche Methode anbieten müsste, um diese Zeiger zu verändern.<br />
Dies würde aber bedeuten, dass man von ausserhalb der Bibliothek diese Werte verändern kann, was aber nur dazu führt, dass Fehler erzeugt werden. Die Werte dürfen nicht von ausserhalb geändert werden!<br />
Was kommt also als nächstes in Frage? Friend, also dass BasicNode sich als friend von NodeContainer deklariert. So könnte ich eine private Methode in BasicNode anbieten, welche NodeContainer bedienen kann. Aber so richtig schön, finde ich diese Lösung nicht. Ich habe noch nie friend verwendet, bisher war es nie nötig, es gab immer einen anderen Weg. Aber hier sehe ich einfach keinen ...</p>
<p>Aber vielleicht könnt ihr mir weiterhelfen ... <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f642.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--slightly_smiling_face"
      title=":)"
      alt="🙂"
    /></p>
<p>Grüssli</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1612387</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1612387</guid><dc:creator><![CDATA[Dravere]]></dc:creator><pubDate>Sun, 09 Nov 2008 14:41:55 GMT</pubDate></item><item><title><![CDATA[Reply to Ein swap Problem wegen Konstanten on Mon, 10 Nov 2008 10:44:35 GMT]]></title><description><![CDATA[<p>Wieso willst Du bei einem swap von NodeContainer die parents aller Nodes änderen? Und woher willst Du den neuen parent bekommen? Von der Bennung her würde man meinen, das parent ebenfalls einen Pointer auf seine Kinder hält, das müsste dann irgenwie auch geändert werden.</p>
<p>Oder geht es Dir nur darum, dass m_parentForNewNodes in NodeContainer mit m_parents der enthaltenen Nodes übereinstimmt?<br />
Wenn swap für Dich das gleiche bedeutet wie für mich, muss Du natürlich nicht nur den m_container austauschen sonderen auch m_parentForNewNodes und dann besteht Dein Problem überhaupt nicht. Das gleiche gilt für m_documentForNewNodes.</p>
<p>Trotzdem sind die Zeiger natürlich irgenwie redundant. Evtl. kannst Du das gesamte Design ja nochmal überdenken.</p>
<p>DJohn</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1612687</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1612687</guid><dc:creator><![CDATA[DJohn@work]]></dc:creator><pubDate>Mon, 10 Nov 2008 10:44:35 GMT</pubDate></item><item><title><![CDATA[Reply to Ein swap Problem wegen Konstanten on Mon, 10 Nov 2008 15:15:06 GMT]]></title><description><![CDATA[<p><a class="plugin-mentions-user plugin-mentions-a" href="https://www.c-plusplus.net/forum/uid/9752">@Dravere</a>: ja, klar macht man das über friend. Also zumindest ich würde es so machen. Ist auch nix unsauberes daran. Gut, du koppelst 2 Klassen dadurch sehr eng aneinander, aber immer noch besser als irgendwas public/protected zu machen, oder accessor/mutator Funktionen zu haben die man eigentlich garnicht braucht bzw. garnicht haben sollte.</p>
<p>Ich habe mir jetzt allerdings NICHT überlegt ob es auch einen einfacheren, besseren Weg gibt.</p>
<p>Was mir viel schwindliger als die ganze friend Geschichte vorkommt ist der NodeWrapper mit dem boost::variant. Wieso verwendest du nicht gleich einen BasicNode* und castest dann entsprechend?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1612827</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1612827</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Mon, 10 Nov 2008 15:15:06 GMT</pubDate></item><item><title><![CDATA[Reply to Ein swap Problem wegen Konstanten on Tue, 11 Nov 2008 00:01:35 GMT]]></title><description><![CDATA[<p>DJohn@work schrieb:</p>
<blockquote>
<p>Oder geht es Dir nur darum, dass m_parentForNewNodes in NodeContainer mit m_parents der enthaltenen Nodes übereinstimmt?</p>
</blockquote>
<p>Genau darum geht es.</p>
<p>DJohn@work schrieb:</p>
<blockquote>
<p>Wenn swap für Dich das gleiche bedeutet wie für mich, muss Du natürlich nicht nur den m_container austauschen sonderen auch m_parentForNewNodes und dann besteht Dein Problem überhaupt nicht. Das gleiche gilt für m_documentForNewNodes.</p>
</blockquote>
<p>Nein, eben nicht. Grundsätzlich kannst du m_parentForNewNodes und m_documentForNewNodes auch als Konstanten anschauen. Diese werden sich nicht verändern, da das eigentliche Objekt immer noch im gleichen Baum ist, nur dessen Inhalt wird getauscht.</p>
<p>Deshalb muss ich beim Swap auch den Inhalt korrigieren, damit dieser in den neuen Baum oder die neue Stelle passt.</p>
<p><a class="plugin-mentions-user plugin-mentions-a" href="https://www.c-plusplus.net/forum/uid/13960">@hustbaer</a>,<br />
Naja, aktuelle habe ich es über friend gelöst. Grundsätzlich funktioniert es sehr gut so, nur fühl ich mich irgendwie Unwohl bei der Benutzung ... vielleicht einfach ungewohnt <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f642.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--slightly_smiling_face"
      title=":)"
      alt="🙂"
    /></p>
<p>Zum NodeWrapper:<br />
Eigentlich soll er nur ein paar Dinge absichern, damit nicht gleich mit dem Boost.Variant Objekt rumgespielt werden kann. Aber du fragst ja hauptsächlich wegen des Boost.Variants.</p>
<p>Die Sache ist die, ich brauche jeweils die entsprechenden Nodes. Grundsätzlich brauche ich BasicNode so gut wie nie. Die Nodes müssen aber auch in eine korrekte Reihenfolge gebracht werden. NodeWrapper ist also eine Art von Position in einer Liste.<br />
Zudem kann ich komplett auf dynamic_cast verzichten. Ich habe mir entsprechende Acceptors gebaut, welche einem erlauben, über nur eine Art von Nodes (oder mehreren) zu iterieren.<br />
Als Beispiel mal einen NodeTypeAcceptor:</p>
<pre><code class="language-cpp">//////////////////////////////////////////////////////////////////////////
// NodeTypeAcceptor : Header file

#ifndef _DSIXML_H_NODE_TYPE_ACCEPTOR_GUARD__
#define _DSIXML_H_NODE_TYPE_ACCEPTOR_GUARD__

#include &quot;NodeWrapper.hpp&quot;

namespace dsi { namespace xml {

	//////////////////////////////////////////////////////////////////////////
	// NodeTypeAcceptor

	template&lt;typename ValidNodeT&gt;
	class NodeTypeAcceptor
	{
		// Typedefs //
	public:
		typedef ValidNodeT ValidNode;

		// Inner classes //
	private:
		class ValidateNode
		{
			// Typedefs //
		public:
			typedef void result_type;

			// Attributes //
		private:
			NodeTypeAcceptor&lt;ValidNode&gt;* m_acceptor;

			// Constructors &amp; Destructor //
		public:
			ValidateNode(NodeTypeAcceptor&lt;ValidNode&gt;* acceptor);
			~ValidateNode();

			// Operators //
		public:
			void operator ()(ValidNode* validNode) const;

			template&lt;typename InvalidNodeT&gt;
			void operator ()(InvalidNodeT*) const;
		};

		// Attributes //
	private:
		ValidNode* m_validNode;

		// Constructors &amp; Destructor //
	public:
		NodeTypeAcceptor();
		~NodeTypeAcceptor();

		// Operators //
	public:
		bool operator ()(NodeWrapper const&amp; node);

		// Methods //
	public:
		bool check(NodeWrapper const&amp; node);
		ValidNode* get_node() const;
	};

} } // dsi::xml

//////////////////////////////////////////////////////////////////////////
// Template implementations

namespace dsi { namespace xml {

	//////////////////////////////////////////////////////////////////////////
	// NodeTypeAcceptor::ValidateNode

	/************************************************************************/
	/* Constructors &amp; Destructor                                            */
	/************************************************************************/

	template&lt;typename ValidNodeT&gt;
	NodeTypeAcceptor&lt;ValidNodeT&gt;::ValidateNode::ValidateNode(NodeTypeAcceptor&lt;ValidNode&gt;* acceptor)
		: m_acceptor(acceptor)
	{
	}

	/************************************************************************/

	template&lt;typename ValidNodeT&gt;
	NodeTypeAcceptor&lt;ValidNodeT&gt;::ValidateNode::~ValidateNode()
	{
	}

	/************************************************************************/
	/* Operators                                                            */
	/************************************************************************/

	template&lt;typename ValidNodeT&gt;
	void NodeTypeAcceptor&lt;ValidNodeT&gt;::ValidateNode::operator ()(ValidNode* validNode) const
	{
		m_acceptor-&gt;m_validNode = validNode;
	}

	/************************************************************************/

	template&lt;typename ValidNodeT&gt;
	template&lt;typename InvalidNodeT&gt;
	void NodeTypeAcceptor&lt;ValidNodeT&gt;::ValidateNode::operator ()(InvalidNodeT*) const
	{
		m_acceptor-&gt;m_validNode = nullptr;
	}

	//////////////////////////////////////////////////////////////////////////
	// NodeTypeAcceptor

	/************************************************************************/
	/* Constructors &amp; Destructor                                            */
	/************************************************************************/

	template&lt;typename ValidNodeT&gt;
	NodeTypeAcceptor&lt;ValidNodeT&gt;::NodeTypeAcceptor()
		: m_validNode(nullptr)
	{
	}

	/************************************************************************/

	template&lt;typename ValidNodeT&gt;
	NodeTypeAcceptor&lt;ValidNodeT&gt;::~NodeTypeAcceptor()
	{
	}

	/************************************************************************/
	/* Operators                                                            */
	/************************************************************************/

	template&lt;typename ValidNodeT&gt;
	bool NodeTypeAcceptor&lt;ValidNodeT&gt;::operator ()(NodeWrapper const&amp; node)
	{
		return check(node);
	}

	/************************************************************************/
	/* Methods                                                              */
	/************************************************************************/

	template&lt;typename ValidNodeT&gt;
	bool NodeTypeAcceptor&lt;ValidNodeT&gt;::check(NodeWrapper const&amp; node)
	{
		ValidateNode validater(this);
		node.apply_visitor(validater);

		return m_validNode != nullptr;
	}

	/************************************************************************/

	template&lt;typename ValidNodeT&gt;
	typename NodeTypeAcceptor&lt;ValidNodeT&gt;::ValidNode* NodeTypeAcceptor&lt;ValidNodeT&gt;::get_node() const
	{
		return m_validNode;
	}

} } // dsi::xml

#endif // _DSIXML_H_NODE_TYPE_ACCEPTOR_GUARD__
</code></pre>
<p>Dieser kann man dann mit einem RangeIterator kombinieren. Dadurch kann man solche Dinge erstellen:</p>
<pre><code class="language-cpp">template&lt;typename NodeT, typename IterT&gt;
	util::RangeIterator&lt;IterT, NodeTypeAcceptor&lt;NodeT&gt; &gt; create_node_type_iterator(IterT first, IterT last)
	{
		return util::RangeIterator&lt;IterT, NodeTypeAcceptor&lt;NodeT&gt; &gt;(first, last);
	}
</code></pre>
<p>RangeIterator aktzeptiert dann nur solche Nodes, welche von NodeTypeAcceptor als korrekt angegeben wurden. Die anderen werden übersprungen.<br />
Dieses überspringen geht sehr rasch, dank den Templates. Es wird nie ein dynamic_cast oder etwas ähnliches benötigt. Ich muss dank den Templates nie irgendetwas casten. Absolute Typsicherheit ... geradezu fanatisch <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f603.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--grinning_face_with_big_eyes"
      title=":D"
      alt="😃"
    /></p>
<p>Ich weiss jetzt nicht, ob es mit diesem Code bereits klar wird. Womöglich nicht ...<br />
Vielleicht müsste ich irgendwann mal die ganze XML Bibliothek zeigen, damit man die Verwendung kennen lernt. Allerdings will ich zuvor noch ein paar Dinge erledigen ... ein paar <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f642.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--slightly_smiling_face"
      title=":)"
      alt="🙂"
    /></p>
<p>Grüssli</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1612991</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1612991</guid><dc:creator><![CDATA[Dravere]]></dc:creator><pubDate>Tue, 11 Nov 2008 00:01:35 GMT</pubDate></item></channel></rss>