Operator überladen: keine passende Funktion für Aufruf



  • Muss?



  • Skym0sh0 schrieb:

    Muss?

    camper oder so kann das sicher besser erklären - aber für ignoranten wie mich gilt folgender Satz:

    non-const referenzen binden nicht an temporäre objekte.

    Vektor(0,0,0) ist ein temporäres Objekt und der CopyCtor will aber eine non-const referenz haben. Ergo bindet das nicht und der Compiler schreit nach keiner passenden gefunden Funktion.



  • Ok, das klingt logisch.

    Ich dachte jetzt, dass beim Copy-Constructor immer const& nötig wäre, und das hat mich halt gewundert, da MSVC grad keinen Fehler bei mir gemeldet hat. (Dass es sinnvoll ist, wie auch grad gezeigt wurde, ist eine ganz andere Geschichte)



  • Danke Shade of Mine, jetzt funktionierts...
    Aber kannst du mit dem binden nochmal erklären? Da steig ich nicht so wirklich durch.

    Das Programm muss ja keinen Sinn ergeben. Ist wirklich nur zur Klausurvorbereitung, damit ich auch mal n Operator überladen habe...



  • Eine Referenz (nicht auf const) kann nicht einem temporären Objekt zugewisen werden.
    Bsp:

    int i;
    int &refOK = i; // In Ordnung
    int &refErr = int(); // Fehler!
    refOK = 5; // In Ordnung
    refErr = 5; // Selbst wenn es kompilieren würde, der Speicherbereich auf den die Referenz verweist, könnte bereits ungültig sein, weil int() nicht mehr existiert
    

    Deswegen müssen bei Funktionsaufrufen konstante Referenzen verwendet werden, wenn sie auch für Temporary aufgerufen werden sollen. Damit kann man nicht ungültigen Speicher bearbeiten.
    Das ist meine Erklärung dafür, aber so genau weiß ich das auch nicht.



  • Die Erklärung ist doch ganz gut.



  • Na ja, warum geht das dan bei konstanten Referenzen?
    Ich mein, der Speicher existiert ja nicht, aber lesen kann man die trotzdem?!
    Deswegen sagte ich das.

    Oh, mir fällt gerade was ein:
    Wenn ein temporäres Objekt an eine Funktion übergeben wird, existiert es ja noch.
    Aber warum gehen dann konstante Referenzen auf Objekte, die eigentlich verworfen werden (temporaries)?



  • der MSVC akzeptiert das komischerweise

    class A
      {
      int i;
    public:
      A () { i = 0; }
      A (A & a) { i = a. i; }
      A (int v) { i = v; }
      A f () { return A (0); }
      };
    
    int main ()
      {
      A a (1);
      A b = a. f ();
      return 0;
      }
    

    bei http://ideone.com kommt "error: no matching function for call to ‘A::A(A)’"

    ISO/IEC 14882:2011 sagt dazu:

    12.8 Copying and moving class objects
    2 A non-template constructor for class X is a copy constructor if its first
    parameter is of type X&, const X&, volatile X& or const volatile X&, and either
    there are no other parameters or else all other parameters have default arguments (8.3.6).



  • Ja existieren tun die noch. Es ist auch leicht falsch zu sagen, dass sie nicht mehr existieren und man deswegen nicht schreiben kann.

    Würde man schreiben können, würde es jedoch keinen Unterschied zwischen const und non-const geben, da das Objekt ja nach der Funktion eh wieder zerstört ist. Beispiel:

    class Foo
    {
    public:
    	Foo()
    	{
    		std::cout << "C-Tor" << std::endl;
    	}
    
    	~Foo()
    	{
    		std::cout << "D-Tor" << std::endl;
    	}
    };
    
    void bar(Foo const& f)
    {
    	std::cout << "Funktion" << std::endl;
    }
    
    int main()
    {
    	{
    		std::cout << "---------------" << std::endl;
    		bar(Foo());
    		std::cout << "---------------" << std::endl;
    	}
    
    	system("PAUSE"); // das system hier soll mal egal sein!!! 
                             // nur damit sich die konsole nicht sofort schliesst
    	return 0;
    }
    

    Und wie du hier an dem Beispiel siehst, sollte folgende Ausgabe kommen:

    ---------------
    C-Tor
    Funktion
    D-Tor
    ---------------
    Press any key to continue . . .
    

    Das schöne ist, in Zeile 15 kannst du das const entfernen und es läuft immer noch (getestet unter meinem Visual Studio 2012 -> MSVC 11.0.5xxx)

    Ich hab jetzt hier gerade weitergetestet:

    #include <iostream>
    #include <fstream>
    #include "BVH_Tree.h"
    
    class Foo
    {
    public:
    	Foo()
    		: x(0)
    	{
    		std::cout << "C-Tor " << x << std::endl;
    	}
    
    	~Foo()
    	{
    		std::cout << "D-Tor " << x << std::endl;
    	}
    
    	int x;
    };
    
    void bar(Foo & f)
    {
    	f.x = 5;
    	std::cout << "Funktion " << f.x << std::endl;
    }
    
    int main()
    {
    	{
    		std::cout << "---------------" << std::endl;
    		bar(Foo());
    		std::cout << "---------------" << std::endl;
    	}
    
    	system("PAUSE");
    	return 0x0;
    }
    

    Und das geht auch noch oO 😮
    Damit sind sowohl meine als auch Nathans Erklärungen von vorher falsch...

    Nachtrag:

    dd++ schrieb:

    ISO/IEC 14882:2011 sagt dazu:

    12.8 Copying and moving class objects
    2 A non-template constructor for class X is a copy constructor if its first
    parameter is of type X&, const X&, volatile X& or const volatile X&, and either
    there are no other parameters or else all other parameters have default arguments (8.3.6).

    D.h. ein Copy Constructor kann auch andere Parameter zusätzlich bekommen? (per default, damit ein parameterloser Aufruf möglich ist)



  • Nathan schrieb:

    Wenn ein temporäres Objekt an eine Funktion übergeben wird, existiert es ja noch.
    Aber warum gehen dann konstante Referenzen auf Objekte, die eigentlich verworfen werden (temporaries)?

    Aus praktischen Gründen.

    Eine non-const referenz auf ein temporäres Objekt ist immer fraglich: warum willst du ein temporäres Objekt ändern? Änderungen verfallen ja direkt wenn die Referenz out of scope geht.

    Wenn man an eine const referenz aber bindet, dann macht das aber oft sinn.

    Beispiel:

    void foo(std::string const& str) {}
    foo("hallo");
    

    hier erstelle ich ja ein temporäres string Objekt und binde es ann eine const referenz. Das macht Sinn und sollte erlaubt sein.

    PS:
    der VC++ ist hier fehlerhaft.
    Testet das ganze einfach auf ideone.
    -> http://ideone.com/6r2pCW



  • so 100%ig blicke ich im Moment noch nicht durch, aber andere Leute hatten das Problem auch schon

    http://stackoverflow.com/questions/6401818/non-const-copy-constructor-and-implicit-conversions-on-return-value



  • dd++ schrieb:

    so 100%ig blicke ich im Moment noch nicht durch, aber andere Leute hatten das Problem auch schon

    Was ist denn unklar?

    VC++ ist, wie so oft, nicht standardkonform. *schocker*



  • Nein!
    VS C++ ist nicht standardkonform?!
    ---
    Zum Thema: Wie genau sieht das eigentlich mit der internen Verwaltung von Referenzen aus, mit C++11 und Referenz auf Temporary?



  • VC++ hat eine Extension, die das binden von non-const LValue-Referenzen an RValues erlaubt. Es gibt auch keinen technischen Grund, der dagegen Spricht, aber aus semantischen Gruenden, wie bereits gesagt, geht das nur bei const-LValue-Referenzen.

    In C++11 hat man die RValue-Referenz eingefuehrt, mit denen das moeglich ist. Beispiel:

    struct Foo {};
    Foo&& foo = Foo{}; // ok
    foo.bar = 42; // ok
    

    Wird in erster Linie fuer Move-Semantiken und Perfect-Forwarding gebraucht.



  • Ich werd nie verstehen warum man ohne /Za kompiliert und dann jammert das der MSVC nicht standardkonform ist. oO



  • kleiner Troll schrieb:

    Ich werd nie verstehen warum man ohne /Za kompiliert und dann jammert das der MSVC nicht standardkonform ist. oO

    Weil man mit /Za nicht weit kommt 😉



  • windows header gehen halt nicht, aber die sind ja kaum überall eingebunden.


Anmelden zum Antworten