Элизия (Copy Elision) в C++

Задумался насчёт элизии. Вроде и хорошо, оптимизирует программы... Но а что, если конструктор по умолчанию и конструктор копирования должны по-разному инициализировать объекты? Как например в следующем коде.

    #include <iostream>

    class A
    {
    private:
        int m_value;
    public:
        A(int value = 0) : m_value {value} { std::cout << "A(int) -> " << m_value << std::endl; }
        A(const A &obj) : m_value {-obj.m_value} { std::cout << "A(const A&) -> " << m_value << std::endl; }
    };

    int main()
    {
        A obj1 { 10 };
        A obj2 { obj1 };
        // obj3.m_value равен 35, а ожидалось -35
        A obj3 { A{35} };

        return 0;
    }

Я у себя получил следующий вывод:

A(int) -> 10
A(const A&) -> -10
A(int) -> 35

Да, вряд ли кто-то станет так инициализировать объект obj3, через анонимный объект, но всё же. Можно ли как-то отключать элизию?


Ответы (2 шт):

Автор решения: user7860670

Заковырка возникает из-за предположения, что в A obj3 { A{35} }; создается анонимный объект. Создание prvalue в С++ теперь вообще никогда само по себе не приводит к созданию объекта. Если необходимо создать именно анонимный объект, то prvalue можно легко метериализовать до вызова конструктора копирования:

#include <iostream>
#include <utility>

class A
{
private:
    int m_value;
public:
    A(int value = 0) : m_value {value} { std::cout << "A(int) -> " << m_value << std::endl; }
    A(const A &obj) : m_value {-obj.m_value} { std::cout << "A(const A&) -> " << m_value << std::endl; }
};

int main()
{
    A obj1 { 10 };
    A obj2 { obj1 };
    // obj3.m_value равен -35
    A obj3 {::std::move(A{35})};

    return 0;
}

online compiler

→ Ссылка
Автор решения: HolyBlackCat

Можно ли как-то отключать элизию?

У некоторых компиляторов есть флаги для этого. Но поскольку copy elision стала обязательной в C++17, отключив ее, вы будете писать уже не на C++, а на каком-то сомнительном его диалекте.

Поэтому решение только одно - писать нормальные классы, которые не ломаются от убирания лишних копий.

→ Ссылка