Błąd kompilacji RVO przy awarii

Wiele dyskusji na temat tego, kiedy można zrobić RVO, ale niewiele o tym, kiedy to się robi. Jak już wspomniano, czasy RVO nie mogą być zagwarantowane zgodnie z normą, aleczy istnieje sposób na zagwarantowanie, że optymalizacja RVO powiedzie się lub odpowiedni kod nie zostanie skompilowany?

Do tej pory udało mi się częściowo wprowadzić błędy linku w przypadku niepowodzenia RVO. W tym celu deklaruję konstruktorów kopii bez ich definiowania. Oczywiście nie jest to ani solidne, ani wykonalne w rzadkich przypadkach, w których muszę zaimplementować jednego lub oba konstruktory kopii, tj.x(x&&) ix(x const&).

To prowadzi mnie do drugiego pytania:Dlaczego twórcy kompilatora wybrali włączenie RVO, gdy zdefiniowano konstruktory kopiowania zdefiniowane przez użytkownika, ale nie wtedy, gdy obecne są tylko domyślne konstruktory kopiowania?

Trzecie pytanie:Czy jest jakiś inny sposób włączenia RVO dla prostych struktur danych?

Ostatnie pytanie (obietnica):Czy znasz jakiś kompilator, który powoduje, że mój kod testowy zachowuje się inaczej niż w przypadku gcc i clang?

Oto przykładowy kod gcc 4.6, gcc 4.8 i clang 3.3, który pokazuje problem. Zachowanie nie zależy od ogólnych ustawień optymalizacji lub debugowania. Oczywiście opcja--no-elide-constructors robi to, co mówi, tzn. wyłącza RVO.

#include <iostream>
using namespace std;

struct x
{
    x () { cout << "original x address" << this << endl; }
};
x make_x ()
{
    return x();
}

struct y
{
    y () { cout << "original y address" << this << endl; }
    // Any of the next two constructors will enable RVO even if only
    // declared but not defined. Default constructors will not do!
    y(y const & rhs);
    y(y && rhs);
};
y make_y ()
{
    return y();
}

int main ()
{
    auto x1 = make_x();
    cout << "copy of  x address" << &x1 << endl;
    auto y1 = make_y();
    cout << "copy of  y address" << &y1 << endl;
}

Wydajność:

original x address0x7fff8ef01dff
copy of  x address0x7fff8ef01e2e
original y address0x7fff8ef01e2f
copy of  y address0x7fff8ef01e2f

RVO wydaje się również nie działać ze zwykłymi strukturami danych:

#include <iostream>

using namespace std;

struct x
{
    int a;
};

x make_x ()
{
    x tmp;
    cout << "original x address" << &tmp << endl;
    return tmp;
}

int main ()
{
    auto x1 = make_x();
    cout << "copy of  x address" << &x1 << endl;
}

Wydajność:

original x address0x7fffe7bb2320
copy of  x address0x7fffe7bb2350

AKTUALIZACJA: Zauważ, że niektóre optymalizacje są bardzo łatwo mylone z RVO. Pomocnicy konstruktorzy lubiąmake_x są przykładem. Widziećten przykład gdzie optymalizacja jest faktycznie egzekwowana przez standard.

questionAnswers(3)

yourAnswerToTheQuestion