Условия для копирования?

Я хотел проверить, работает ли следующая оптимизация:

  • РОО
  • Именованный RVO
  • Копировать elision при передаче аргумента по значению

Итак, я написал эту небольшую программу:

#include <algorithm>
#include <cstddef>
#include <iostream>
#include <vector>

struct Foo {
    Foo(std::size_t length, char value) : data(length, value) { }

    Foo(const Foo & rhs) : data(rhs.data) { std::cout << "*** COPY ***" << std::endl; }

    Foo & operator= (Foo rhs) {
        std::cout << "*** ASSIGNMENT ***" << std::endl;
        std::swap(data, rhs.data); // probably expensive, ignore this please
        return *this;
    }

    ~Foo() { }

    std::vector<char> data;
};

Foo TestRVO() { return Foo(512, 'r'); }

Foo TestNamedRVO() { Foo result(512, 'n'); return result; }

void PassByValue(Foo inFoo) {}

int main()
{
    std::cout << "\nTest RVO: " << std::endl;
    Foo rvo = TestRVO();

    std::cout << "\nTest named RVO: " << std::endl;
    Foo named_rvo = TestNamedRVO();

    std::cout << "\nTest PassByValue: " << std::endl;
    Foo foo(512, 'a');
    PassByValue(foo);

    std::cout << "\nTest assignment: " << std::endl;
    Foo f(512, 'f');
    Foo g(512, 'g');
    f = g;
}

И я скомпилировал его с включенными оптимизациями:

$ g++ -o test -O3 main.cpp ; ./test

Это выводится:

Test RVO: 

Test named RVO: 

Test PassByValue: 
*** COPY ***

Test assignment: 
*** COPY ***
*** ASSIGNMENT ***

В соответствии с выходом RVO и названным RVO работают, как ожидалось. Однако для оператора присваивания не выполняется копирование, а при вызове PassByValue.

Не разрешено ли исключение копирования для определенных пользователем конструкторов-копий? (Я знаю, что RVO явно разрешено стандартом, но я не знаю о том, как копировать elision при передаче по значению.) Есть ли способ проверить копию elision без определения конструкторов копирования?

Ответ 1

То, как вы используете конструктор копирования, не может быть отменено, поскольку скопированный объект все еще существует после вызова.

Если вы попробуете это так, это может сработать лучше:

PassByValue(Foo(512, 'a')); 

Все оптимизации разрешены, но не требуются, поэтому каждый компилятор должен решить, что он может и будет делать.

Ответ 2

В стандарте говорится (в пункте 12.8.15):

Это исключение операций копирования разрешено в следующих обстоятельства (которые могут быть объединены для устранения нескольких копий):

  • в return в функции с class return type, когда выражение это название энергонезависимого автоматический объект с тем же cv-неквалифицированный тип как функция возвращаемый тип, операция копирования может быть опущено путем создания автоматического объект непосредственно в функции возвращаемое значение

  • когда временный класс объект, который не был связан с ссылка (12.2) будет скопирована на объект класса с тем же cv-неквалифицированный тип, копия операция может быть опущена построение временного объекта прямо в цель пропущенная копия

Ни один из этих случаев не применяется здесь, поэтому исключение не допускается. Первое - очевидно (нет возврата). Второе не разрешено, потому что объект, который вы проходите, не является временным.

Обратите внимание, что ваш код по-прежнему прекрасен, потому что вам все равно придется создавать копию. Чтобы избавиться от этой копии, вам нужно будет использовать семантику перемещения С++ 0x.