C ++ 11右值引用调用拷贝构造函数 [英] C++11 rvalue reference calling copy constructor too

查看:798
本文介绍了C ++ 11右值引用调用拷贝构造函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在测试一些C ++ 11的功能。
我遇到了r值引用和移动构造函数。



我实现了我的第一个移动构造函数,这里是:

  #include< iostream> 
#include< vector>
using namespace std;

class TestClass {

public:
TestClass(int s):
size(s),arr(new int [s]){
}
〜TestClass(){
if(arr)
delete arr;
}
//复制构造函数
TestClass(const TestClass& other):
size(other.size),arr(new int [other.size]){
std :: copy(other.arr,other.arr + other.size,arr);
}

//移动构造函数
TestClass(TestClass&& other){
arr = other.arr;
size = other.size;

other.arr = nullptr;
other.size = 0;
}

私人:
int size;
int * arr;
};

int main(){
vector< TestClass> vec;

clock_t start = clock();
for(int i = 0; i <500000; i ++){
vec.push_back(TestClass(1000));
}
clock_t stop = clock();
cout<< stop-start<< endl;

return 0;
}

代码工作正常。无论如何把一个std :: cout里面的复制构造函数,我注意到它被调用!和很多次..(移动构造函数500000次,复制构造函数524287次)。



更令人惊讶的是,如果我从代码中注释掉复制构造函数,整个程序得到的快得多,这次move构造函数被称为1024287次。



任何线索?

解决方案

noexcept 放在您的移动构造函数中:

  TestClass(TestClass&&&& other)noexcept {



在C ++ 03

pre> 矢量< T> :: push_back(T)

有强异常保证。这意味着如果 push_back 抛出异常,向量将保持与调用 push_back

如果move构造函数抛出异常,此保证是有问题的。



$ c> vector 重新分配,它会像 元素从旧缓冲区移动到新的。然而,如果这些移动中的任何一个抛出异常(除了第一个),则它保持在旧的缓冲器已经被修改的状态,并且新的缓冲器还没有包含它应该的所有东西。 向量无法将旧缓冲区恢复到其原始状态,因为它必须将元素移回到这样做,这些移动也可能失败。



因此,规定了C ++ 11的规则:


  1. 如果 T 有一个 noexcept 移动构造函数,可用于将元素从旧缓冲区移动到


  2. 否则如果 T 有一个复制构造函数, p>


  3. 否则(如果没有可访问的拷贝构造函数),那么将使用move构造函数,但在这种情况下,强异常安全性保证不再


澄清:规则2中的复制构造函数是指构造函数采用 const T& ,而不是那些所谓的 T& 复制构造函数。 : - )


I've been testing some C++11 features from some some. I came across r-value references and move constructors.

I implemented my first move constructor, here it is:

#include <iostream>
#include <vector>
using namespace std;

class TestClass{

public:
    TestClass(int s):
        size(s), arr(new int[s]){
    }
    ~TestClass(){
        if (arr)
            delete arr;
    }
    // copy constructor
    TestClass(const TestClass& other):
            size(other.size), arr(new int[other.size]){
        std::copy(other.arr, other.arr + other.size, arr);
    }

    // move constructor
    TestClass(TestClass&& other){
        arr=other.arr;
        size=other.size;

        other.arr=nullptr;
        other.size=0;
    }

private:
    int size;
    int * arr;
};

int main(){
    vector<TestClass> vec;

    clock_t start=clock();
    for(int i=0;i<500000;i++){
        vec.push_back(TestClass(1000));
    }
    clock_t stop=clock();
    cout<<stop-start<<endl;

    return 0;
}

The code works fine. Anyway putting a std::cout inside the copy constructor i noticed that it gets called! And a lot of times.. (move constructor 500000 times, copy constructor 524287 times).

What surprised me more is that if i comment out the copy constructor from the code, the whole program gets a lot faster, and this time the move constructor is called 1024287 times.

Any clue?

解决方案

Put noexcept on your move constructor:

TestClass(TestClass&& other) noexcept {

Elaboration: I was going to give this one Pierre, but unfortunately the cppreference source is only approximately correct.

In C++03

vector<T>::push_back(T)

has the "strong exception guarantee". That means that if the push_back throws an exception, the vector is left in the same state it had prior to the call to push_back.

This guarantee is problematic if the move constructor throws an exception.

When the vector reallocates, it would like to move the elements from the old buffer to the new. However if any one of those moves throws an exception (besides the first), then it is left in a state where the old buffer has been modified, and the new buffer doesn't yet contain everything it is supposed to. The vector can't restore the old buffer to its original state because it would have to move elements back to do so, those moves might also fail.

So a rule was laid down for C++11:

  1. If T has a noexcept move constructor, that can be used to move the elements from the old buffer to the new.

  2. Otherwise if T has a copy constructor, that will be used instead.

  3. Otherwise (if there is no accessible copy constructor), then the move constructor will be used after all, however in this case, the strong exception safety guarantee is no longer given.

Clarification: "copy constructor" in rule 2 means a constructor taking a const T&, not one of those weenie so-called T& copy constructors. :-)

这篇关于C ++ 11右值引用调用拷贝构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆