<?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[Konstante Getter-Funktionen?]]></title><description><![CDATA[<p>Guten Abend,</p>
<p>ich habe mir angewöhnt, in meinen Klassen Getter-Funktionen als konstant zu definieren:</p>
<pre><code class="language-cpp">class A
{
    int a_;

    public:
        const int a() { return a_; }
};
</code></pre>
<p>Nun compilierte ich eines meiner Programme mal mit <code>-Wextra</code> und sah, dass für diese Fälle Warnungen ausgegeben werden, in Scott Meyers &quot;Effektiv C++ programmieren&quot; steht jedoch, man solle konstante Getter vorziehen.</p>
<p>Wo liegt nun aber der Fehler? Welches ist das bessere Design und sollte aus welchen Gründen vorgezogen werden?</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/306288/konstante-getter-funktionen</link><generator>RSS for Node</generator><lastBuildDate>Sat, 08 Aug 2026 07:36:43 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/306288.rss" rel="self" type="application/rss+xml"/><pubDate>Mon, 23 Jul 2012 22:25:45 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Konstante Getter-Funktionen? on Mon, 23 Jul 2012 22:25:45 GMT]]></title><description><![CDATA[<p>Guten Abend,</p>
<p>ich habe mir angewöhnt, in meinen Klassen Getter-Funktionen als konstant zu definieren:</p>
<pre><code class="language-cpp">class A
{
    int a_;

    public:
        const int a() { return a_; }
};
</code></pre>
<p>Nun compilierte ich eines meiner Programme mal mit <code>-Wextra</code> und sah, dass für diese Fälle Warnungen ausgegeben werden, in Scott Meyers &quot;Effektiv C++ programmieren&quot; steht jedoch, man solle konstante Getter vorziehen.</p>
<p>Wo liegt nun aber der Fehler? Welches ist das bessere Design und sollte aus welchen Gründen vorgezogen werden?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2235058</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2235058</guid><dc:creator><![CDATA[ichnicht]]></dc:creator><pubDate>Mon, 23 Jul 2012 22:25:45 GMT</pubDate></item><item><title><![CDATA[Reply to Konstante Getter-Funktionen? on Mon, 23 Jul 2012 22:29:04 GMT]]></title><description><![CDATA[<p>also ich kenne auch nur den tipp mit dem const... vlt interpretierst du die Fehlermeldung deines Compilers falsch...</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2235061</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2235061</guid><dc:creator><![CDATA[Clundsch]]></dc:creator><pubDate>Mon, 23 Jul 2012 22:29:04 GMT</pubDate></item><item><title><![CDATA[Reply to Konstante Getter-Funktionen? on Mon, 23 Jul 2012 22:29:14 GMT]]></title><description><![CDATA[<pre><code class="language-cpp">int a() const { return a_; }
</code></pre>
<p>Bei dir ist der zurück gegebene Wert konstant (was reichlich sinnlos ist, daher die Warnung), hier ist a() konstant, wodurch a() auch auf konstante A angewendet werden kann, da dieses A garantiert nicht verändert werden kann (Ausnahmen durch mutable mal ausgenommen).</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2235062</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2235062</guid><dc:creator><![CDATA[SeppJ]]></dc:creator><pubDate>Mon, 23 Jul 2012 22:29:14 GMT</pubDate></item><item><title><![CDATA[Reply to Konstante Getter-Funktionen? on Mon, 23 Jul 2012 22:32:39 GMT]]></title><description><![CDATA[<p>SeppJ schrieb:</p>
<blockquote>
<pre><code class="language-cpp">int a() const { return a_; }
</code></pre>
<p>Bei dir ist der zurück gegebene Wert konstant (was reichlich sinnlos ist, daher die Warnung), hier ist a() konstant, wodurch a() auch auf konstante A angewendet werden kann, da dieses A garantiert nicht verändert werden kann (Ausnahmen durch mutable mal ausgenommen).</p>
</blockquote>
<p>Tut mir Leid, ich habe mich wirklich selten dämlich ausgedrückt. <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>Ich meinte natürlich Getter mit konstantem Rückgabewert und keine konstanten Funktionen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2235064</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2235064</guid><dc:creator><![CDATA[ichnicht]]></dc:creator><pubDate>Mon, 23 Jul 2012 22:32:39 GMT</pubDate></item><item><title><![CDATA[Reply to Konstante Getter-Funktionen? on Mon, 23 Jul 2012 22:34:46 GMT]]></title><description><![CDATA[<p>Clundsch schrieb:</p>
<blockquote>
<p>also ich kenne auch nur den tipp mit dem const... vlt interpretierst du die Fehlermeldung deines Compilers falsch...</p>
</blockquote>
<pre><code>Warnung: Typkennzeichner an Funktions-Rückgabewert ignoriert [-Wignored-qualifiers]
</code></pre>
<p>-Wignored-qualifiers ist laut Erklärungen genau für solche Fälle mit <code>const</code> gedacht.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2235066</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2235066</guid><dc:creator><![CDATA[ichnicht]]></dc:creator><pubDate>Mon, 23 Jul 2012 22:34:46 GMT</pubDate></item><item><title><![CDATA[Reply to Konstante Getter-Funktionen? on Mon, 23 Jul 2012 23:15:43 GMT]]></title><description><![CDATA[<p>also bei mir funktioniert</p>
<pre><code>int const a() {}
</code></pre>
<p>und</p>
<pre><code>const int a() {}
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2235084</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2235084</guid><dc:creator><![CDATA[Clundsch]]></dc:creator><pubDate>Mon, 23 Jul 2012 23:15:43 GMT</pubDate></item><item><title><![CDATA[Reply to Konstante Getter-Funktionen? on Mon, 23 Jul 2012 23:21:08 GMT]]></title><description><![CDATA[<p>[c]</p>
<p>ichnicht schrieb:</p>
<blockquote>
<p>Ich meinte natürlich Getter mit konstantem Rückgabewert und keine konstanten Funktionen.</p>
</blockquote>
<p>Das meinst du vielleicht, aber nicht Scott Meyers. Der meint konstante Memberfunktionen in seinem Tipp 21 (zweite Ausgabe, die Nummern wurden später durcheinander gewürfelt).</p>
<p>Clundsch schrieb:</p>
<blockquote>
<p>also bei mir funktioniert</p>
<pre><code>int const a() {}
</code></pre>
<p>und</p>
<pre><code>const int a() {}
</code></pre>
</blockquote>
<p>Das ist auch beides exakt das gleiche und beides nicht sehr sinnvoll, was meine Ahnung im anderen Thread bestätigt, dass du const nicht wirklich verstanden hast. Ist mir jetzt aber zu spät, um noch mal groß auszuholen. Du wirst dich gedulden müssen, bis jemand anderes es dir erklärt oder bis ich morgen an diesen Thread denke (sofern ich überhaupt dran denke, was nicht unbedingt der Fall ist :-\ )</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2235085</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2235085</guid><dc:creator><![CDATA[SeppJ]]></dc:creator><pubDate>Mon, 23 Jul 2012 23:21:08 GMT</pubDate></item><item><title><![CDATA[Reply to Konstante Getter-Funktionen? on Mon, 23 Jul 2012 23:32:17 GMT]]></title><description><![CDATA[<p>SeppJ schrieb:</p>
<blockquote>
<p>[c]</p>
<p>ichnicht schrieb:</p>
<blockquote>
<p>Ich meinte natürlich Getter mit konstantem Rückgabewert und keine konstanten Funktionen.</p>
</blockquote>
<p>Das meinst du vielleicht, aber nicht Scott Meyers. Der meint konstante Memberfunktionen in seinem Tipp 21 (zweite Ausgabe, die Nummern wurden später durcheinander gewürfelt).</p>
</blockquote>
<p>In 55 specific ways to improve your programs and designs, Tipp 3 schreibt er das schon. Sein Beispiel:</p>
<p>Scott Meyers schrieb:</p>
<blockquote>
<p>const Rational operator*(const Rational&amp; lhs, const Rational&amp; rhs);</p>
</blockquote>
<p>Das soll verhindern dass jemand sowas schreibt:</p>
<p>(a * b) = c;</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2235088</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2235088</guid><dc:creator><![CDATA[Mechanics]]></dc:creator><pubDate>Mon, 23 Jul 2012 23:32:17 GMT</pubDate></item><item><title><![CDATA[Reply to Konstante Getter-Funktionen? on Mon, 23 Jul 2012 23:37:03 GMT]]></title><description><![CDATA[<p>Meyers erwähnt das im Zusammenhang mit überladenen Operatoren die &quot;user defined types&quot; (=eigene Klassen) als Returntyp haben. (Bei Gettern macht es zugegebenerweise allerdings genau so Sinn, vorausgesetzt sie getten einen UDT).<br />
Einem int Returntyp ein top-level const umzubinden ist wohl höchst sinnfrei.</p>
<p>Dazu zwei doofe Fragen...</p>
<ol>
<li>Darf eine T&amp;&amp; Referenz wirklich an einen Returnwert vom Typ &quot;T const&quot; gebunden werden? (Spricht: funktioniert move noch wenn man den Returnwert top-level const macht?)</li>
<li>Wie ist &quot;this&quot; bei den Default Copy- und Move-Assignment Operatoren qualifiziert - &quot;&amp;&quot; oder &quot;&amp;&amp;&quot;?</li>
</ol>
<p>Wenn (1) = ja, dann ist das top-level const wohl zumindest nicht schädlich.<br />
Wenn (2) = &quot;&amp;&quot;, dann ist es allerdings (C++11 konformen Compiler und passend definierte Klasse vorausgesetzt) nicht nötig.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2235092</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2235092</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Mon, 23 Jul 2012 23:37:03 GMT</pubDate></item><item><title><![CDATA[Reply to Konstante Getter-Funktionen? on Tue, 24 Jul 2012 00:14:47 GMT]]></title><description><![CDATA[<p>Jetzt bin ich verwirrt und weiß erst recht nicht mehr, wann eine Funktion einen konstanten und wann sie keinen konstanten Rückgabewert haben sollte.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2235095</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2235095</guid><dc:creator><![CDATA[ichnicht]]></dc:creator><pubDate>Tue, 24 Jul 2012 00:14:47 GMT</pubDate></item><item><title><![CDATA[Reply to Konstante Getter-Funktionen? on Tue, 24 Jul 2012 01:06:58 GMT]]></title><description><![CDATA[<p>Wenn du dich nicht mit C++11 Feinheiten rumschlagen willst, UND diverse (mMn. sehr weit hergeholte) Programmierfehler (siehe Mechanics' Beitrag) verhindern willst, dann wenn</p>
<ol>
<li>Die Funktion einen Wert &quot;by value&quot; zurückgibt<br />
UND</li>
<li>Der Returnwert einen &quot;user defined type&quot; hat (user defined type = class/struct)</li>
</ol>
<p>Natürlich gibt es ein paar Ausnahmen, aber wenn du denen begegnest stolperst du eh von selbst drüber, weil etwas nicht mehr geht was ganz klar gehen sollte.</p>
<p>Heisst bei <code>int</code> , <code>float</code> , <code>char</code> etc. sowie sämtlichen Zeigern macht ein <em>top-level const</em> keinen Sinn. Es schadet nicht, aber es bringt auch nix. Weil nämlich C++ von sich aus schon die besagten weit hergeholten Programmierfehler verhindert. Wenn du <em>sehr</em> auf Konsistenz Wert legst kannst du es natürlich auch gerne bei solchen Typen schreiben. Sonst würde ich sagen lass es.</p>
<p>Und zum Thema Zeiger noch um einem möglichen Misverständnis vorzugreifen:</p>
<pre><code class="language-cpp">MeineKlasse* const MeineFunktion(); // &lt;-- DAS ist ein top-level const (Zeiger ist const)
MeineKlasse const* MeineFunktion(); // &lt;-- das ist KEIN top-level const (MeineKlasse Objekt ist const)

const MeineKlasse* MeineFunktion(); // &lt;-- das ist AUCH KEIN top-level const, ist das selbe wie MeineKlasse const*
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2235099</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2235099</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Tue, 24 Jul 2012 01:06:58 GMT</pubDate></item><item><title><![CDATA[Reply to Konstante Getter-Funktionen? on Tue, 24 Jul 2012 01:30:11 GMT]]></title><description><![CDATA[<p>SeppJ schrieb:</p>
<blockquote>
<p>Clundsch schrieb:</p>
<blockquote>
<p>also bei mir funktioniert</p>
<pre><code>int const a() {}
</code></pre>
<p>und</p>
<pre><code>const int a() {}
</code></pre>
</blockquote>
<p>Das ist auch beides exakt das gleiche</p>
</blockquote>
<p>Kleine Anmerkung, das ist nicht ganz exakt das Gleiche, sondern unterschiedliche Funktionen, deren Typ sich unterscheidet. Die Eleminierung von top-level cv-Qualikationenen, ebenso wie die Substitution von Array- durch Zeigerdeklarationen bzw. von Funktionen durch Funktionszeiger findet nur für die Parameter statt.<br />
Funktionen, die Arrays oder Funktionen zurückgeben gibt es nicht, solche Deklarationen sind ill-formed. Wer Spaß daran hat, kann aber gerne seine void-Funktionen durch const volatile void-Funktionen ersetzen.<br />
Diese cv-Qualifikation ändert allerdings nichts am Typ eines Ausdrucks, der einen Funktionsaufruf darstellt, wenn der Rückgabetyp ein Skalar ist.</p>
<blockquote>
<ol>
<li>Darf eine T&amp;&amp; Referenz wirklich an einen Returnwert vom Typ &quot;T const&quot; gebunden werden? (Spricht: funktioniert move noch wenn man den Returnwert top-level const macht?)</li>
</ol>
</blockquote>
<p>nein. Etwas anderes gilt nat. für deduzierbare Templateparameter, ein T&amp;&amp; kann auch als T=const U deduziert werden. Der gewöhnliche Move-Konstruktor/Zuweisungsoperator nimmt aber nur modifizierbare rvalues. in jedem Fall kommt es auf den Typ des Ausdrucks an, der rechts steht, und der ist für Skalare stets unqualifiziert.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2235101</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2235101</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Tue, 24 Jul 2012 01:30:11 GMT</pubDate></item><item><title><![CDATA[Reply to Konstante Getter-Funktionen? on Tue, 24 Jul 2012 02:51:20 GMT]]></title><description><![CDATA[<p>camper schrieb:</p>
<blockquote>
<blockquote>
<ol>
<li>Darf eine T&amp;&amp; Referenz wirklich an einen Returnwert vom Typ &quot;T const&quot; gebunden werden? (Spricht: funktioniert move noch wenn man den Returnwert top-level const macht?)</li>
</ol>
</blockquote>
<p>nein. Etwas anderes gilt nat. für deduzierbare Templateparameter, ein T&amp;&amp; kann auch als T=const U deduziert werden. Der gewöhnliche Move-Konstruktor/Zuweisungsoperator nimmt aber nur modifizierbare rvalues. in jedem Fall kommt es auf den Typ des Ausdrucks an, der rechts steht, und der ist für Skalare stets unqualifiziert.</p>
</blockquote>
<p>OK, Skalare mal beiseite...</p>
<p>Wenn ein Move-Konstruktor nicht mit einer &quot;const UDT fun();&quot; funktioniert, dann ist<br />
a) Clang 3.0 verbuggt (MSVC auch, aber OK, ... QEE)<br />
und<br />
b) top-level const im Returntyp mit UDTs BÖSE weil es Move verhindert</p>
<p>Oder übersehe ich da jetzt was (bezüglich (b)).</p>
<p>ps: ich verstehe deine Antwort bezüglich &quot;const int a()&quot; vs &quot;int const a()&quot; nicht. Ob const vor oder hinter dem int ist doch egal, ist doch in beiden Fällen top level const... nicht?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2235105</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2235105</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Tue, 24 Jul 2012 02:51:20 GMT</pubDate></item><item><title><![CDATA[Reply to Konstante Getter-Funktionen? on Tue, 24 Jul 2012 06:50:50 GMT]]></title><description><![CDATA[<p>hustbaer schrieb:</p>
<blockquote>
<p>Wenn ein Move-Konstruktor nicht mit einer &quot;const UDT fun();&quot; funktioniert, dann ist<br />
a) Clang 3.0 verbuggt (MSVC auch, aber OK, ... QEE)</p>
</blockquote>
<p>Nein, das ist schon richtig so. Ein Move Konstruktor nimmt normalerweise eine UDT&amp;&amp; und keine const UDT&amp;&amp;. Es ist ja normalerweise gerade erst der Zweck eines Move Konstruktors, das Objekt, von dem gemoved wird, zu ändern...</p>
<p>hustbaer schrieb:</p>
<blockquote>
<p>b) top-level const im Returntyp mit UDTs BÖSE weil es Move verhindert</p>
</blockquote>
<p>top-level const im Returntyp ist nicht prinzipiell böse, aber sowas wie const int als Return Type ist wohl sinnlos. Die einzig mir bekannte sinnvolle Anwendung von top-level const auf einem Returntype, wenn ein Objekt by Value returned wird, ist operator overloading.</p>
<p>hustbaer schrieb:</p>
<blockquote>
<p>ps: ich verstehe deine Antwort bezüglich &quot;const int a()&quot; vs &quot;int const a()&quot; nicht. Ob const vor oder hinter dem int ist doch egal, ist doch in beiden Fällen top level const... nicht?</p>
</blockquote>
<p>Ich glaub, da hat er einfach einmal das const übersehen <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f609.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--winking_face"
      title=";)"
      alt="😉"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/2235115</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2235115</guid><dc:creator><![CDATA[dot]]></dc:creator><pubDate>Tue, 24 Jul 2012 06:50:50 GMT</pubDate></item><item><title><![CDATA[Reply to Konstante Getter-Funktionen? on Tue, 24 Jul 2012 08:23:07 GMT]]></title><description><![CDATA[<p>dot schrieb:</p>
<blockquote>
<p>Ich glaub, da hat er einfach einmal das const übersehen <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f609.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--winking_face"
      title=";)"
      alt="😉"
    /></p>
</blockquote>
<p>Err ja, hatte da sowas wie</p>
<pre><code class="language-cpp">int a();
const int a();
</code></pre>
<p>gelesen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2235136</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2235136</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Tue, 24 Jul 2012 08:23:07 GMT</pubDate></item><item><title><![CDATA[Reply to Konstante Getter-Funktionen? on Tue, 24 Jul 2012 09:32:48 GMT]]></title><description><![CDATA[<p>hustbaer schrieb:</p>
<blockquote>
<p>Wenn du dich nicht mit C++11 Feinheiten rumschlagen willst, UND diverse (mMn. sehr weit hergeholte) Programmierfehler (siehe Mechanics' Beitrag) verhindern willst, dann wenn</p>
<ol>
<li>Die Funktion einen Wert &quot;by value&quot; zurückgibt<br />
UND</li>
<li>Der Returnwert einen &quot;user defined type&quot; hat (user defined type = class/struct)</li>
</ol>
<p>Natürlich gibt es ein paar Ausnahmen, aber wenn du denen begegnest stolperst du eh von selbst drüber, weil etwas nicht mehr geht was ganz klar gehen sollte.</p>
<p>Heisst bei <code>int</code> , <code>float</code> , <code>char</code> etc. sowie sämtlichen Zeigern macht ein <em>top-level const</em> keinen Sinn. Es schadet nicht, aber es bringt auch nix. Weil nämlich C++ von sich aus schon die besagten weit hergeholten Programmierfehler verhindert. Wenn du <em>sehr</em> auf Konsistenz Wert legst kannst du es natürlich auch gerne bei solchen Typen schreiben. Sonst würde ich sagen lass es.</p>
</blockquote>
<p>Und wenn ich mich mit C++11 Feinheiten herumschlagen will? <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>
]]></description><link>https://www.c-plusplus.net/forum/post/2235164</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2235164</guid><dc:creator><![CDATA[ichnicht]]></dc:creator><pubDate>Tue, 24 Jul 2012 09:32:48 GMT</pubDate></item><item><title><![CDATA[Reply to Konstante Getter-Funktionen? on Tue, 24 Jul 2012 10:35:54 GMT]]></title><description><![CDATA[<p>SeppJ schrieb:</p>
<blockquote>
<pre><code class="language-cpp">int a() const { return a_; }
</code></pre>
<p>Bei dir ist der zurück gegebene Wert konstant (was reichlich sinnlos ist, daher die Warnung), hier ist a() konstant, wodurch a() auch auf konstante A angewendet werden kann, da dieses A garantiert nicht verändert werden kann (Ausnahmen durch mutable mal ausgenommen).</p>
</blockquote>
<p>Das stimmt so, aber das Hauptziel hier ist wohl eher anzuzeigen, dass das Objekt selber bei der Ausführung von a() nicht verändert wird, was bei einem getter ja wohl immer der Fall sein sollte. Oder anders: alle Methoden, die das Objekt (sprich darauf wo this zeigt) nicht verändern, sollten als const deklariert werden. Dann dürfen allerdings auch nur aus dieser Methode heraus als const deklarierte Methoden aufgerufen werden. Das überprüft dann der Compiler für dich.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2235203</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2235203</guid><dc:creator><![CDATA[kwarnke]]></dc:creator><pubDate>Tue, 24 Jul 2012 10:35:54 GMT</pubDate></item><item><title><![CDATA[Reply to Konstante Getter-Funktionen? on Tue, 24 Jul 2012 18:08:24 GMT]]></title><description><![CDATA[<p>dot schrieb:</p>
<blockquote>
<p>hustbaer schrieb:</p>
<blockquote>
<p>Wenn ein Move-Konstruktor nicht mit einer &quot;const UDT fun();&quot; funktioniert, dann ist<br />
a) Clang 3.0 verbuggt (MSVC auch, aber OK, ... QEE)</p>
</blockquote>
<p>Nein, das ist schon richtig so. Ein Move Konstruktor nimmt normalerweise eine UDT&amp;&amp; und keine const UDT&amp;&amp;. Es ist ja normalerweise gerade erst der Zweck eines Move Konstruktors, das Objekt, von dem gemoved wird, zu ändern...</p>
</blockquote>
<p>Clang 3.0 bindet einen <code>const UDT</code> Returnwert direkt an <code>UDT&amp;&amp;</code> Parameter ( <code>UDT</code> = konkreter Typ, kein Template-Parameter!).<br />
Nach dem was camper geschrieben hat dürfte er das ja nicht. Oder doch?</p>
<p>Also konkret, im Beispiel unten macht Clang 3.0 2x move und nicht 1x move und 1x copy.<br />
Es sei denn ich hatte in meinem Test-Code nen Fehler -- muss das heute Abend nochmal genauer untersuchen.</p>
<p>dot schrieb:</p>
<blockquote>
<p>hustbaer schrieb:</p>
<blockquote>
<p>b) top-level const im Returntyp mit UDTs BÖSE weil es Move verhindert</p>
</blockquote>
<p>top-level const im Returntyp ist nicht prinzipiell böse, aber sowas wie const int als Return Type ist wohl sinnlos. Die einzig mir bekannte sinnvolle Anwendung von top-level const auf einem Returntype, wenn ein Objekt by Value returned wird, ist operator overloading.</p>
</blockquote>
<p>Also wenn ich euch richtig verstanden habe, dann...</p>
<pre><code class="language-cpp">std::string good();
std::string const bad();

std::string pipe(std::string s) { return s; }
void consumer(std::string s) { /* konsumiert irgendwie s - ist ja egal wie */ }

void test()
{
    consumer(pipe(good())); // 1x move
    consumer(pipe(bad())); // 1x copy
}
</code></pre>
<p>...und das ist für mich böse, weil ... wieso move verhindern?</p>
<p>Wenn man <code>good() = &quot;foo&quot;;</code> oder ähnliches verhindern will ohne move zu verhindern, dann muss <code>std::string</code> seinen <code>operator =</code> doch bloss &quot;&amp;&quot; qualifizieren:</p>
<pre><code class="language-cpp">template &lt;...&gt;
class basic_string
{
// ...
    basic_string&amp; operator = (basic_string other) &amp;; // tadaa
};
</code></pre>
<p>const im Returntyp ist dabei nicht nötig.</p>
<p>Daher auch die Frage ob die Signatur eines compilergenerierten operator = &quot;&amp;&quot; oder &quot;&amp;&amp;&quot; qualifiziert ist.</p>
<p>dot schrieb:</p>
<blockquote>
<p>hustbaer schrieb:</p>
<blockquote>
<p>ps: ich verstehe deine Antwort bezüglich &quot;const int a()&quot; vs &quot;int const a()&quot; nicht. Ob const vor oder hinter dem int ist doch egal, ist doch in beiden Fällen top level const... nicht?</p>
</blockquote>
<p>Ich glaub, da hat er einfach einmal das const übersehen <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f609.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--winking_face"
      title=";)"
      alt="😉"
    /></p>
</blockquote>
<p>Nachdem camper SO selten Fehler macht dachte ich mir ich frag' sicherheitshalber lieber <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>
]]></description><link>https://www.c-plusplus.net/forum/post/2235340</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2235340</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Tue, 24 Jul 2012 18:08:24 GMT</pubDate></item><item><title><![CDATA[Reply to Konstante Getter-Funktionen? on Tue, 24 Jul 2012 18:13:22 GMT]]></title><description><![CDATA[<p>ichnicht schrieb:</p>
<blockquote>
<p>hustbaer schrieb:</p>
<blockquote>
<p>Wenn du dich nicht mit C++11 Feinheiten rumschlagen willst, UND diverse (mMn. sehr weit hergeholte) Programmierfehler (siehe Mechanics' Beitrag) verhindern willst, dann wenn</p>
<ol>
<li>Die Funktion einen Wert &quot;by value&quot; zurückgibt<br />
UND</li>
<li>Der Returnwert einen &quot;user defined type&quot; hat (user defined type = class/struct)</li>
</ol>
<p>Natürlich gibt es ein paar Ausnahmen, aber wenn du denen begegnest stolperst du eh von selbst drüber, weil etwas nicht mehr geht was ganz klar gehen sollte.</p>
<p>Heisst bei <code>int</code> , <code>float</code> , <code>char</code> etc. sowie sämtlichen Zeigern macht ein <em>top-level const</em> keinen Sinn. Es schadet nicht, aber es bringt auch nix. Weil nämlich C++ von sich aus schon die besagten weit hergeholten Programmierfehler verhindert. Wenn du <em>sehr</em> auf Konsistenz Wert legst kannst du es natürlich auch gerne bei solchen Typen schreiben. Sonst würde ich sagen lass es.</p>
</blockquote>
<p>Und wenn ich mich mit C++11 Feinheiten herumschlagen will? <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>
</blockquote>
<p>Dann schreib lieber deine Klassen so, dass der Assignment-Operator nicht auf Rvalues funktioniert (siehe Beispiel mit basic_string oben).<br />
Das entspricht mMn. nämlich am ehesten dem was eingebaute Typen machen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2235343</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2235343</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Tue, 24 Jul 2012 18:13:22 GMT</pubDate></item><item><title><![CDATA[Reply to Konstante Getter-Funktionen? on Wed, 25 Jul 2012 08:01:20 GMT]]></title><description><![CDATA[<p>Ich hab grade mal mit r-values gespielt und das Beispiel von oben etwas verändert. Das Ergebnis verwundert mich:</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;cstring&gt;
using namespace std;

struct X {
  X(char const* str) : ptr(0) {ptr = new char[strlen(str)+1]; strcpy(ptr, str);}
  X(X&amp;&amp; other)      : ptr(other.ptr) {other.ptr = 0; cout &lt;&lt; &quot;move &quot; &lt;&lt; ptr &lt;&lt; ' ';}
  X(X const&amp; other) : ptr(0)         {ptr = new char[strlen(other.ptr)+1]; strcpy(ptr, other.ptr); cout &lt;&lt; &quot;copy &quot; &lt;&lt; ptr &lt;&lt; ' ';}
  ~X() {delete ptr;}

  char* ptr;
};

X good() {X x(&quot;good&quot;); return x;}
X const bad() {X x(&quot;bad&quot;); return x;}

X pipe(X x) { return x; }
void consumer(X x) { std::cout &lt;&lt; &quot;consume &quot; &lt;&lt; x.ptr &lt;&lt; '\n'; }

int main()
{
    consumer(good());      //erwartet: max. 1 move
    consumer(bad());       //erwartet: max. 1 move
    consumer(pipe(good()));//erwartet: max. 2 move
    consumer(pipe(bad())); //erwartet: max. 1 move, 1 copy
}
</code></pre>
<p>Ergebnis gcc-4.5.1: (ideone)</p>
<pre><code>consume good
consume bad
copy good consume good
copy bad consume bad
</code></pre>
<p>wieso kopiert er den &quot;good&quot;? sollte doch perfekt movebar sein? Dass es überall ein move weniger ist dürfte (N)RVO sein (habs auch mit unbenannten RV's in good() und bad() ausprobiert.</p>
<p>Ergebnis VS10 (debug):</p>
<pre><code>move good consume good
move bad consume bad
move good move good consume good
move bad move bad consume bad
</code></pre>
<p>offenbar bindet der schamlos rrefs an const r-values. Was sagt der Standard dazu?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2235460</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2235460</guid><dc:creator><![CDATA[pumuckl]]></dc:creator><pubDate>Wed, 25 Jul 2012 08:01:20 GMT</pubDate></item><item><title><![CDATA[Reply to Konstante Getter-Funktionen? on Wed, 25 Jul 2012 08:40:49 GMT]]></title><description><![CDATA[<p>Ein move ist auch innerhalb der Funktionen beim return denkbar (in pipe sogar erforderlich) während die Kopie möglicherweise ausgelassen wird.<br />
Eigentlich:</p>
<pre><code class="language-cpp">//return    call     return         call
    consumer(good());      //erwartet:    move      move
    consumer(bad());       //erwartet:    move      copy
    consumer(pipe(good()));//erwartet:    move      move     move (immer)   move
    consumer(pipe(bad())); //erwartet:    move      copy     move (immer)   move
</code></pre>
<p>gcc 4.5.1 kennt die move-Regel beim lvalue-return noch nicht, gcc-4.6.3 macht das dann richtig:</p>
<pre><code>consume good
consume bad
move good consume good
move bad consume bad
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2235462</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2235462</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Wed, 25 Jul 2012 08:40:49 GMT</pubDate></item><item><title><![CDATA[Reply to Konstante Getter-Funktionen? on Wed, 25 Jul 2012 08:35:37 GMT]]></title><description><![CDATA[<p>Klitzekleine Nachlässigkeit...</p>
<pre><code class="language-cpp">~X() {delete[] ptr;}
</code></pre>
<p>Wenn man hier mitliest ist man ganz versessen darauf new/delete Fehler zu erspähen... <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f609.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--winking_face"
      title=";)"
      alt="😉"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/2235466</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2235466</guid><dc:creator><![CDATA[Sollte schon im Büro sein]]></dc:creator><pubDate>Wed, 25 Jul 2012 08:35:37 GMT</pubDate></item><item><title><![CDATA[Reply to Konstante Getter-Funktionen? on Wed, 25 Jul 2012 09:30:42 GMT]]></title><description><![CDATA[<p>Wie schon ausgeführt, kann der obige Code nicht schlüssig demonstrieren, dass msvc konstante Objekte on modifizierbare rvalue-Referenzen bindet. Weil nicht klar wird, welche Copy/Move-Operationen ausgelassen werden. Eine kleine Modifikation ist erforderlich:</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;cstring&gt;
using namespace std;

struct X {
  X(char const* str) : ptr(0) {ptr = new char[strlen(str)+1]; strcpy(ptr, str);}
  X(X&amp;&amp; other)      : ptr(other.ptr) {other.ptr = 0; cout &lt;&lt; &quot;move &quot; &lt;&lt; ptr &lt;&lt; ' ';}
  X(X const&amp; other) : ptr(0)         {ptr = new char[strlen(other.ptr)+1]; strcpy(ptr, other.ptr); cout &lt;&lt; &quot;copy &quot; &lt;&lt; ptr &lt;&lt; ' ';}
  ~X() {delete []ptr;}

  char* ptr;
};

X good() { X x(&quot;good&quot;); return *&amp;x;}
X const bad() { X x(&quot;bad&quot;); return *&amp;x;}

X pipe(X x) { return *&amp;x; }
void consumer(X x) { std::cout &lt;&lt; &quot;consume &quot; &lt;&lt; x.ptr &lt;&lt; '\n'; }

int main()
{
    // * = copy/move can be elided        return    call     return   call
    consumer(good());      //erwartet:    copy      move*
    consumer(bad());       //erwartet:    copy      copy*
    consumer(pipe(good()));//erwartet:    copy      move*    copy     move*
    consumer(pipe(bad())); //erwartet:    copy      copy*    copy     move*
}
</code></pre>
<p>Hier muss beim return in jedem Fall eine Copy gemacht werden, jeder zusätzliche Konstruktoraufruf würde also vom Funktionsaufruf stammen.<br />
gcc ist hier mal wieder zu aggresiv:</p>
<pre><code>consume good
consume bad
move good consume good
move bad consume bad
</code></pre>
<p>Hier wird also von gcc NRVO angewendet, obwohl das nicht zulässig ist. Also lieber so:</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;cstring&gt;
using namespace std;

struct X {
  X(char const* str) : ptr(str) {}
  X(X&amp;&amp; other)      : ptr(other.ptr) {cout &lt;&lt; &quot;move &quot; &lt;&lt; ptr &lt;&lt; ' ';}
  X(X const&amp; other) : ptr(other.ptr) {cout &lt;&lt; &quot;copy &quot; &lt;&lt; ptr &lt;&lt; ' ';}
  ~X() {}

  char* ptr;
};

X a(&quot;good&quot;), b(&quot;bad&quot;);

X good() { return a;}
X const bad() { return b;}

X pipe(X x) { return x.ptr==a.ptr?a:b; }
void consumer(X x) { std::cout &lt;&lt; &quot;consume &quot; &lt;&lt; x.ptr &lt;&lt; '\n'; }

int main()
{
    // * = copy/move can be elided        return    call     return   call
    consumer(good());      //erwartet:    copy      move*
    consumer(bad());       //erwartet:    copy      copy*
    consumer(pipe(good()));//erwartet:    copy      move*    copy     move*
    consumer(pipe(bad())); //erwartet:    copy      copy*    copy     move*
}
</code></pre>
<p>jetzt erhalte ich</p>
<pre><code>copy good consume good
copy bad consume bad
copy good copy good consume good
copy bad copy bad consume bad
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2235491</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2235491</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Wed, 25 Jul 2012 09:30:42 GMT</pubDate></item><item><title><![CDATA[Reply to Konstante Getter-Funktionen? on Wed, 25 Jul 2012 14:38:43 GMT]]></title><description><![CDATA[<p>camper schrieb:</p>
<blockquote>
<pre><code class="language-cpp">X good() { X x(&quot;good&quot;); return *&amp;x;}
X const bad() { X x(&quot;bad&quot;); return *&amp;x;}
 
X pipe(X x) { return *&amp;x; }
</code></pre>
<p>Hier muss beim return in jedem Fall eine Copy gemacht werden, jeder zusätzliche Konstruktoraufruf würde also vom Funktionsaufruf stammen.<br />
gcc ist hier mal wieder zu aggresiv:</p>
</blockquote>
<p>MSVC:</p>
<pre><code>move good consume good
move bad consume bad
move good move good consume good
move bad move bad consume bad
</code></pre>
<p>camper schrieb:</p>
<blockquote>
<p>Also lieber so:</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;cstring&gt;
using namespace std;
 
struct X {
  X(char const* str) : ptr(str) {}
  X(X&amp;&amp; other)      : ptr(other.ptr) {cout &lt;&lt; &quot;move &quot; &lt;&lt; ptr &lt;&lt; ' ';}
  X(X const&amp; other) : ptr(other.ptr) {cout &lt;&lt; &quot;copy &quot; &lt;&lt; ptr &lt;&lt; ' ';}
  ~X() {}
 
  char* ptr;
};
</code></pre>
</blockquote>
<pre><code>main.cpp(6): error C2440: 'initializing' : cannot convert from 'const char *' to 'char *'
</code></pre>
<p><img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f609.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--winking_face"
      title=";)"
      alt="😉"
    /> Hatte das auch erst so versucht, dann doch aber mit strcpy &amp; co gearbeitet. Mit der anderen Implementierung von X wie vorher und good()/bad()/pipe() wie bei dir bekomme ich das selbe: 1-2x copy, kein move.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2235601</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2235601</guid><dc:creator><![CDATA[pumuckl]]></dc:creator><pubDate>Wed, 25 Jul 2012 14:38:43 GMT</pubDate></item><item><title><![CDATA[Reply to Konstante Getter-Funktionen? on Wed, 25 Jul 2012 14:51:48 GMT]]></title><description><![CDATA[<p>pumuckl schrieb:</p>
<blockquote>
<p>camper schrieb:</p>
<blockquote>
<pre><code class="language-cpp">X good() { X x(&quot;good&quot;); return *&amp;x;}
X const bad() { X x(&quot;bad&quot;); return *&amp;x;}
 
X pipe(X x) { return *&amp;x; }
</code></pre>
<p>Hier muss beim return in jedem Fall eine Copy gemacht werden, jeder zusätzliche Konstruktoraufruf würde also vom Funktionsaufruf stammen.<br />
gcc ist hier mal wieder zu aggresiv:</p>
</blockquote>
<p>MSVC:</p>
<pre><code>move good consume good
move bad consume bad
move good move good consume good
move bad move bad consume bad
</code></pre>
</blockquote>
<p>Interessant.<br />
Also nochmal Faktencheck:</p>
<p>n3337 12.8/31 schrieb:</p>
<blockquote>
<p>When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class<br />
object, even if the copy/move constructor and/or destructor for the object have side effects. In such cases,<br />
the implementation treats the source and target of the omitted copy/move operation as simply two different<br />
ways of referring to the same object, and the destruction of that object occurs at the later of the times<br />
when the two objects would have been destroyed without the optimization.123 This elision of copy/move<br />
operations, called copy elision, is permitted in the following circumstances (which may be combined to<br />
eliminate multiple copies):<br />
123) Because only one object is destroyed instead of two, and one copy/move constructor is not executed, there is still one<br />
object destroyed for each one constructed.<br />
— in a return statement in a function with a class return type, when the expression is the name of a<br />
non-volatile automatic object (other than a function or catch-clause parameter) with the same cvunqualified<br />
type as the function return type, the copy/move operation can be omitted by constructing<br />
the automatic object directly into the function’s return value<br />
— in a throw-expression, [...]<br />
— when a temporary class object that has not been bound to a reference (12.2) would be copied/moved<br />
to a class object with the same cv-unqualified type, the copy/move operation can be omitted by<br />
constructing the temporary object directly into the target of the omitted copy/move<br />
— when the exception-declaration of an exception handler (Clause 15) declares [...]</p>
</blockquote>
<p>in</p>
<pre><code class="language-cpp">return *&amp;x;
</code></pre>
<p>liegt kein temporäres Objekt vor, also kommt der 3. Anstrich nicht in Frage.<br />
*&amp;x ist auch nicht <em>der Name</em> eines lokalen Objektes, sondern schlicht ein anderer Ausdruck, der nur zufällig auf ein solches Objekt verweist. Der Standard gibt gcc also nicht das Recht, hier die Kopie auszulassen.</p>
<p>n3337 12.8/32 schrieb:</p>
<blockquote>
<p>When the criteria for elision of a copy operation are met or would be met save for the fact that the source<br />
object is a function parameter, and the object to be copied is designated by an lvalue, overload resolution to<br />
select the constructor for the copy is first performed as if the object were designated by an rvalue. If overload<br />
resolution fails, or if the type of the first parameter of the selected constructor is not an rvalue reference to<br />
the object’s type (possibly cv-qualified), overload resolution is performed again, considering the object as an<br />
lvalue. [ Note: This two-stage overload resolution must be performed regardless of whether copy elision will<br />
occur. It determines the constructor to be called if elision is not performed, and the selected constructor<br />
must be accessible even if the call is elided. —end note ]</p>
</blockquote>
<p>Da schon geklärt wurde, dass Copy-Elision nicht ausgeführt werden kann, und der Grund dafür in der Form des Ausdrucks zu suchen ist und nicht etwa in der Tatsache, dass ein Funktionsargument zurückgegeben wird, kommt diese Optimierung auch nicht in Frage. Es muss kopiert werden.<br />
clang macht es übrigens richtig.</p>
<p>Wie verhält sich msvc, bei der Variante mit globalen Objekten?</p>
<p>pumuckl schrieb:</p>
<blockquote>
<pre><code>main.cpp(6): error C2440: 'initializing' : cannot convert from 'const char *' to 'char *'
</code></pre>
</blockquote>
<p>Muss nat. const char* hin, hatte ich so getestet, nur dann hier beim Posten vergessen, zu ändern.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2235611</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2235611</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Wed, 25 Jul 2012 14:51:48 GMT</pubDate></item><item><title><![CDATA[Reply to Konstante Getter-Funktionen? on Wed, 25 Jul 2012 22:27:09 GMT]]></title><description><![CDATA[<p>camper schrieb:</p>
<blockquote>
<p>Wie schon ausgeführt, kann der obige Code nicht schlüssig demonstrieren, dass msvc konstante Objekte on modifizierbare rvalue-Referenzen bindet. Weil nicht klar wird, welche Copy/Move-Operationen ausgelassen werden.</p>
</blockquote>
<p>Du hast (wie meistens) vollkommen Recht - und ich habe MSVC anscheinend zu unrecht beschuldigt. Und Clang vermutlich auch.</p>
<p>camper schrieb:</p>
<blockquote>
<p>Eine kleine Modifikation ist erforderlich:</p>
<p>(...)</p>
<p>Hier muss beim return in jedem Fall eine Copy gemacht werden, jeder zusätzliche Konstruktoraufruf würde also vom Funktionsaufruf stammen.<br />
gcc ist hier mal wieder zu aggresiv:</p>
<pre><code>consume good
consume bad
move good consume good
move bad consume bad
</code></pre>
<p>Hier wird also von gcc NRVO angewendet, obwohl das nicht zulässig ist.</p>
</blockquote>
<p>Bekomm' ich mit MSVC das selbe Ergebnis.</p>
<p>Ich hab meinen Test jetzt nochmal umgeschrieben:</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;utility&gt;

using namespace std;

struct foo {
	explicit foo(char const* s) : m_str(s) { cout &lt;&lt; &quot;init &quot; &lt;&lt; m_str &lt;&lt; &quot;\n&quot;; }
	foo(foo const&amp; other)  : m_str(other.m_str) { cout &lt;&lt; &quot;copy &quot; &lt;&lt; m_str &lt;&lt; &quot;\n&quot;; }
	foo(foo&amp;&amp; other) : m_str(other.m_str) { cout &lt;&lt; &quot;move &quot; &lt;&lt; m_str &lt;&lt; &quot;\n&quot;; }
	~foo() { cout &lt;&lt; &quot;destroy &quot; &lt;&lt; m_str &lt;&lt; &quot;\n&quot;; }

	foo&amp; operator = (foo const&amp; other) { m_str = other.m_str; cout &lt;&lt; &quot;copy-assign &quot; &lt;&lt; m_str &lt;&lt; &quot;\n&quot;; return *this; }
	foo&amp; operator = (foo&amp;&amp; other) { m_str = other.m_str; cout &lt;&lt; &quot;move-assign &quot; &lt;&lt; m_str &lt;&lt; &quot;\n&quot;; return *this; }

private:
	char const* m_str;
};

foo good() { return foo(&quot;good&quot;); }
foo const bad() { return foo(&quot;bad&quot;); }

void consume(foo) { }

template &lt;class T&gt; void consume2(T&amp;&amp; t) {
	consume(forward&lt;T&gt;(t));
}

int main()
{
	consume2(good());
	cout &lt;&lt; &quot;\n&quot;;
	consume2(bad());
//	cout &lt;&lt; &quot;\n&quot;;
//	good() = foo(&quot;nicht so gut&quot;);
}
</code></pre>
<p>Damit bekomme ich von MSVC 11...</p>
<pre><code>init good
move good
destroy good
destroy good

init bad
copy bad
destroy bad
destroy bad
</code></pre>
<p>...was ich für vernünftig halte.</p>
<p>(EDIT: GCC 4.5.1 macht das selbe: <a href="http://ideone.com/v4fkC" rel="nofollow">http://ideone.com/v4fkC</a> )</p>
<p>Ich schliesse daraus: Returntyp mit top-level const verhindert Zuweisung, aber auch (in manchen Fällen) move.</p>
<p>Den Assignment-Operator auf Lvalues einzuschränken ist mMn. ganz klar die bessere Lösung.<br />
Einerseits muss man es nur 1x pro Klasse machen, und nicht pro Funktion die die Klasse als Returntyp verwendet. Und andrerseits verhindert es die unerwünschte Zuweisung, lässt uns aber das erwünschte move.</p>
<p>Dummerweise kann MSVC 11 das noch nicht.</p>
<p>BTW: gibt's ne Seite ala ideone wo man Clang 3.0, Clang 3.1, GCC 4.6 und/oder GCC 4.7 ausprobieren kann (inklusive Code Ausführen)?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2235770</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2235770</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Wed, 25 Jul 2012 22:27:09 GMT</pubDate></item></channel></rss>