Следующий код ведет себя по-разному с или без пользовательского конструктора копирования в соответствии с GCC 8.0.1:
#include <cassert>
struct S {
int i;
int *p;
S() : i(0), p(&i) {}
// S(const S &s) : i(s.i), p(&i) {} // #1
// S(const S &s) : i(s.i), p(s.p) {} // #2
// S(const S &s) = delete; // #3
};
S make_S() {return S{};}
int main()
{
S s = make_S();
assert(s.p == &s.i);
}
С любым из прокомментированных пользовательских конструкторов копирования (даже с # 2, который выполняет простое поверхностное копирование), утверждение не потерпит неудачу, что означает гарантированная копия elision работает как положено.
Однако без какого-либо пользовательского конструктора копирования утверждение не выполняется, что означает объект s
в main
функция не построена по умолчанию. Почему это происходит? Разве гарантированное копирование здесь не работает?
Цитирование из C ++ 17 Рабочий проект §15.2 Временные объекты Пункт 3 (https://timsong-cpp.github.io/cppwp/class.temporary#3):
Когда объект класса типа X передается или вернулся из функции, если каждый конструктор копирования, конструктор перемещения и деструктор X либо тривиален, либо удален, а X имеет по меньшей мере один не удаленный конструктор копирования или перемещения, реализациям разрешено создавать временный объект для хранения параметр функции или объект результата. … [ Заметка: Эта широта предоставляется, чтобы позволить объектам типа класса передаваться или возвращаться из функций в регистрах. - конечная нота]
В вашем случае, когда я сделал конструкторы копирования и перемещения по умолчанию:
S(const S &) = default;
S(S &&) = default;
утверждение не удалось также с GCC и Clang. Обратите внимание, что неявно определенные конструкторы тривиальны.
Других решений пока нет …