返回 std::vector 时未调用复制构造函数

copy constructor not called when returning a std::vector

我想知道这里发生了什么:

class Test {
public:
    Test() { std::cout << "Constructor" << std::endl; }
    Test(const Test &) { std::cout << "Copy" << std::endl; }
    Test(const Test &&) { std::cout << "Move" << std::endl; }
    ~Test() { std::cout << "Destructor" << std::endl; }
};
std::vector<Test> getTestVektor() {
    std::vector<Test> TestVektor(1);
    return TestVektor;
}
Test getTest() {
    Test TestVariable;
    return TestVariable;
}

int main() {
    {
        std::vector<Test> TestVektor = getTestVektor();
    }
    std::cout << std::endl;
    {
        Test TestVarible = getTest();
    }
    std::cout << std::endl;
    {
        std::vector<Test> TestVektor(1);
        std::vector<Test> TestVektor2 = TestVektor;
    }
    return 0;
}

使用 VisualStudio 2012 编译:

Constructor
Destructor

Constructor
Move
Destructor
Destructor

Constructor
Copy
Destructor
Destructor

第一种情况可以用复制省略来解释。但这与调用移动构造函数的第二种情况相反。

另一种解释是,函数中的std::vector将其内容释放并传递给第二个std::vector,因此没有调用复制构造函数。但是第三个案例表明,事实并非如此。

那么,这里发生了什么?或者这只是疯狂的编译器优化?

第一种情况(在最坏的情况下)移动向量(因此只传输内部指针,没有Test的copy/move)。

第 3 种情况复制 vector,您必须执行以下操作来移动它而不是复制:

{
    std::vector<Test> TestVektor(1);
    std::vector<Test> TestVektor2 = std::move(TestVektor);
}

One could explain the first case with copy elision.

TestVektor 是从 return 从 getTestVektor 编辑的临时向量构建的移动。一个、两个或一个都没有被省略。

But that's contrary to the second case, where the move constructor was called.

Copy/move 省略不是强制性的。它可以用于 getTest 的 return 和 TestVarible 的复制初始化,但它没有用于其中之一。

我测试的 GCC 和 Clang 版本都被省略了。

Another explanation would be, that the std::vector in the function releases its contents and passes it to the second std::vector

这正是 std::vector 的移动构造函数所做的。

但是第三种情况是复制赋值,而不是移动构造。

总之,这里发生的事情主要由 std::vector 的移动构造函数解释,但第二种情况也显示了 copy/move 省略的可观察(缺乏)副作用。

仅供参考,来自 clang 的输出,带有 -O2:

Constructor
Destructor

Constructor
Destructor

Constructor
Copy
Destructor
Destructor

为什么 visual studio 会在情况 2 中调用移动对我来说是个谜。您是否禁用了优化?