2

После кода отлично работает (показывая РВО):Какое влияние ключевое слово «явное» на Оптимизацию возвращаемого значения (RVO)?

struct A { 
    A (int) { cout << "A::A()\n"; } // constructor 
    A (const A&) { cout << "A::A(const A&)\n"; } // copy constructor 
}; 

A foo() { return A(0); } 

int main() { 
    A a = foo(); 
} 

Выход:

A::A() // --> which means copy constructor is not called 

Если я отмечаю конструктор копирования как explicit:

explicit A (const A&) { ... } 

Тогда ошибки компиляции из:

explicit.cpp: In function ‘A foo()’: 
explicit.cpp:10:22: error: no matching function for call to ‘A::A(A)’ 
A foo() { return A(0); } 
        ^
explicit.cpp:5:3: note: candidate: A::A(int) 
    A (int) { cout << "A::A()\n"; } 
^
explicit.cpp:5:3: note: no known conversion for argument 1 from ‘A’ to ‘int’ 
explicit.cpp: In function ‘int main()’: 
explicit.cpp:14:13: error: no matching function for call to ‘A::A(A)’ 
    A a = foo(); 
      ^
explicit.cpp:5:3: note: candidate: A::A(int) 
    A (int) { cout << "A::A()\n"; } 
^
explicit.cpp:5:3: note: no known conversion for argument 1 from ‘A’ to ‘int’ 

Почему это происходит, разве RVO не работает так, как есть?

+1

Это не имеет никакого отношения к RVO. –

+0

Похоже, что на это отвечает: http://stackoverflow.com/questions/29472565/explicit-copy-constructor-compile-error – NathanOliver

+0

@ KonradRudolph, но без ключевого слова «явно» RVO имеет место и не делает несколько копий 'A'. Почему это не должно продолжаться, когда мы отмечаем конструктор как «явный»? Возможно, Q не имеет прямого отношения к RVO, но я обнаружил некоторую косвенную связь между этими двумя вещами. @NathanOliver, спасибо за указание. Это Q показывает наблюдение. Однако это Q о «Почему?» – iammilind

ответ

7

РВО может игнорировать копию, но правила языка требуют, чтобы копия (или движение) должны еще быть возможно:

[C++14: 12.8/31]: При соблюдении определенных критериев, реализация может опустить копию/переместите конструкцию объекта класса, даже если конструктор, выбранный для операции копирования/перемещения и/или деструктор объекта, имеет побочные эффекты. [..]

[C++14: 12.8/32]:[..][Примечание: Это разрешение перегрузки двухступенчатая должны быть выполнены независимо от того, будет ли происходить копия элизия. Он определяет вызывающий конструктор, если elision не выполняется, и выбранный конструктор должен быть доступен, даже если вызов отменяется. -end примечание]

Вы сделали копию невозможно, добавив explicit, и движение не представляется возможным, потому что ваша копия конструктора блокирует создание неявно определенного конструктора перемещения.

Вы могли бы позволить движение вместо добавив свой собственный конструктор перемещения, возможно, один дефолт:

A(A&&) = default; 

Но это лишь еще один способ соблюдения того же правила языка.

C++ 17 частично смягчит правило, добавив некоторые гарантии копирования, которые не будут подвержены этому ограничению.

+0

(Игнорирование семантики перемещения для целей этого ответа, поскольку в коде в вопросе явно нет.) –