RVO und/oder Bug?



  • Hallo,

    ich bin gerade auf etwas Komisches gestoßen (VS2013 Update 1):
    (Sinn: Will die Klasse in einer DLL haben und Create exportieren, ScopeLock macht aber nur am Stack Sinn, daher dachte ich mir, ein Stack-Objekt "rauszumoven" :D)

    class ScopeLock
    {
    	CRITICAL_SECTION& criticalSection;
    	bool locked;
    public:
    	ScopeLock(CRITICAL_SECTION& criticalSection);
    	~ScopeLock();
    	ScopeLock(ScopeLock&&) = delete;
    	ScopeLock() = delete;
    	ScopeLock(const ScopeLock&) = delete;
    	ScopeLock& operator=(const ScopeLock&) = delete;
    	static ScopeLock Create(CRITICAL_SECTION& criticalSection);
    	void Lock();
    	void Unlock();
    };
    
    ScopeLock::ScopeLock(CRITICAL_SECTION& criticalSection) : criticalSection(criticalSection), locked(true)
    {
    	cout << "new lock: " <<  this << endl;
    
    	EnterCriticalSection(&criticalSection);
    }
    
    ScopeLock::~ScopeLock()
    {
    	if(locked)
    	{
    		cout << "unlock: " << this << endl;
    
    		LeaveCriticalSection(&criticalSection);
    	}
    }
    
    ScopeLock ScopeLock::Create(CRITICAL_SECTION& criticalSection)
    {
    	return ScopeLock(criticalSection);
    }
    
    void ScopeLock::Lock()
    {
    	locked = true;
    	EnterCriticalSection(&criticalSection);
    }
    
    void ScopeLock::Unlock()
    {
    	LeaveCriticalSection(&criticalSection);
    	locked = false;
    }
    
    int main()
    {
    	CRITICAL_SECTION cs;
    	InitializeCriticalSection(&cs);
    
    	{
    		auto lock = ScopeLock::Create(cs);
    	}
    }
    

    Ausgabe:
    new lock: 003BF7DC
    unlock: 003BF7DC

    Visual Studio zeigt in Zeile 35 und 56 einen Fehler (rot unterstrichen, egal wie oft ich rescanne oder neu öffne), kompiliert aber trotzdem fehlerfrei 😃
    Die Fehler bei mouseover lauten in etwa "error: move constr. can't be referenced - is deleted".

    Was ist da los? Da wird scheinbar RVO angewandt? Und warum will der da eigentlich den move constructor aufrufen und nicht den copy constructor?



  • Wieso meinst du dass der Copy-Ctor aufgerufen werden sollte?
    Also vorausgesetzt es gäbe sowohl einen Copy-Ctor als auch einen Move-Ctor... dann würde ich schon erwarten dass er den Move-Ctor nimmt. Das Ding dass du zurückgibst ist ja wohl ganz klar ne Rvalue...



  • Ähh klar... sry, war schon zu spät :p



  • Rote Kringel sind völlig uninteressant! Wenn der Compiler keine Fehler oder Warnungen ausspuckt ist alles ok.



  • Und was passiert da jetzt genau?



  • Wenn ich den move constructor definiere, verschwinden die scheinbaren Fehler, jedoch wird er nie aufgerufen.


  • Mod

    Das sollte nicht kompilieren. Es ist egal, ob die Temporarys elidiert werden oder nicht, ein applikabler Move/Copy-Ctor muss vorhanden sein. Das ist offensichtlich nicht der Fall.

    When the criteria for elision of a copy operation are met [...], overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue.
    If overload resolution fails, or if the type of the first parameter of the selected constructor is not an rvalue reference to the object’s type (possibly cv-qualified), overload resolution is performed again, considering the object as an
    lvalue.
    [ Note: This two-stage overload resolution must be performed regardless of whether copy elision will occur. It determines the constructor to be called if elision is not performed, and the selected constructor must be accessible even if the call is elided. — end note ]

    Edit: Man kann jetzt diskutieren, was genau der Standard von der ausgewählten Funktion erwartet. Hier darf sie jedoch nicht deleted sein, weil Overload Resolution den Move-Konstruktor auswählt, und

    A program that refers to a deleted function implicitly or explicitly, other than to declare it, is ill-formed.
    [ Note: [...] If a function is overloaded, it is referenced only if the function is selected by overload resolution. — end note ]


Anmelden zum Antworten