复制条款的条件?

Sta*_*ked 10 c++

我想验证以下优化是否按预期工作:

  • RVO
  • 命名为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;
}
Run Code Online (Sandbox Code Playgroud)

我在启用优化的情况下编译了它:

$ g++ -o test -O3 main.cpp ; ./test
Run Code Online (Sandbox Code Playgroud)

这是输出:

Test RVO: 

Test named RVO: 

Test PassByValue: 
*** COPY ***

Test assignment: 
*** COPY ***
*** ASSIGNMENT ***
Run Code Online (Sandbox Code Playgroud)

根据输出RVO并命名为RVO按预期工作.但是,不会为赋值运算符和调用时执行复制省略PassByValue.

用户定义的复制构造函数不允许复制省略吗?(我知道标准明确允许使用RVO,但是当通过值传递时我不知道复制省略.)有没有办法在不定义复制构造函数的情况下验证复制省略?

Bjö*_*lex 10

标准说(第12.8.15段):

在以下情况下允许复制操作的这种省略(可以组合以消除多个副本):

  • 在具有类返回类型的函数的return语句中,当表达式是具有与函数返回类型相同的cv-nonqualified类型的非易失性自动对象的名称时,可以通过构造自动对象来省略复制操作直接进入函数的返回值

  • 当一个尚未绑定到引用(12.2)的临时类对象被复制到具有相同cv-unqualified类型的类对象时,可以通过将临时对象直接构造到目标中来省略复制操作.省略副本

这些情况都不适用于此,因此不允许使用省略号.第一个是显而易见的(没有回报).第二个是不允许的,因为您传入的对象不是临时的.

请注意,您的代码仍然正常,因为您无论如何都必须创建副本.要废除该副本,您必须使用C++ 0x的移动语义.


Bo *_*son 9

您使用复制构造函数的方式无法省略,因为复制的对象在调用后仍然存在.

如果你这样尝试,它可能会更好:

PassByValue(Foo(512, 'a')); 
Run Code Online (Sandbox Code Playgroud)

所有优化都是允许的,但不是必需的,因此由每个编译器决定它能做什么和将做什么.