Зависит ли поведение гарантированного разрешения копирования от существования определяемого пользователем конструктора копирования?

Следующий код ведет себя по-разному с или без пользовательского конструктора копирования в 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, который выполняет простое поверхностное копирование), утверждение не потерпит неудачу, что означает, что гарантированное разрешение копирования работает должным образом.

Однако без какого-либо пользовательского конструктора копирования утверждение не выполняется, что означает объект s в main функция не построена по умолчанию. Почему это происходит? Разве гарантированное копирование здесь не работает?

1 ответ

Решение

Цитирование из C++17 Рабочий проект §15.2 Временные объекты, пункт 3 ( https://timsong-cpp.github.io/cppwp/class.temporary):

Когда объект класса типа X передается или возвращается из функции, если каждый конструктор копирования, конструктор перемещения и деструктор X является тривиальным или удаленным, а X имеет по крайней мере один не удаленный конструктор копирования или перемещения, реализации разрешено создавать временный объект для хранения параметра функции или объекта результата. ... [ Примечание: эта широта предоставляется, чтобы позволить объектам типа класса передаваться или возвращаться из функций в регистрах. - конец примечания]

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

S(const S &) = default;
S(S &&) = default;

утверждение не удалось также с GCC и Clang. Обратите внимание, что неявно определенные конструкторы тривиальны.

Другие вопросы по тегам