移动shared_ptr <myclass> </myclass>向量的构造函数

时间:2013-11-27 15:20:04

标签: c++ boost c++11 move shared-ptr

我理解你是否希望传递MyClass对象的向量并且它是一个临时变量,如果为MyClass定义了一个移动构造函数,那么这将被调用,但是如果你传递{{1}的向量会发生什么}或boost::shared_ptr<MyClass>? shared_ptr是否有一个移动构造函数,然后调用MyClass的移动构造函数?

3 个答案:

答案 0 :(得分:3)

是的,std::shared_ptr<T>有一个移动构造函数,以及一个可以从相关共享指针移动的模板化构造函数,但它根本不会触及托管对象。新构造的共享指针共享托管对象的所有权(如果有的话),并且move-from指针被解除(“null”)。

示例:

struct Base {};                // N.B.: No need for a virtual destructor
struct Derived : Base {};

auto p = std::make_shared<Derived>();
std::shared_ptr<Base> q = std::move(p);

assert(!p);

答案 1 :(得分:3)

  

如果为MyClass定义了一个移动构造函数,那么这将被称为

通常不是。移动向量通常是我转移托管数组的所有权,将移动的向量留空。物体本身没有被触及。 (我认为如果两个向量具有不兼容的分配器可能会有异常,但这超出了我需要处理的任何内容,所以我不确定那里的细节。)

  

shared_ptr是否有一个移动构造函数,然后调用MyClass的移动构造函数?

没有。同样,它有一个移动构造函数,它将MyClass对象的所有权转移到新指针,将旧指针留空。对象本身没有受到影响。

答案 2 :(得分:3)

如果您的意思是移动std::vector<std::shared_ptr<MyClass>>。然后甚至不会调用std::shared_ptr的移动构造函数。因为移动操作直接在std::vector级别完成。

例如,std::vector<T>可以实现为指向T数组和size成员的指针。用于此的移动构造函数可以实现为:

template <typename T>
class vector {
public:
    /* ... other members */
    vector(vector &&another): _p(another._p), _size(another._size) {
        /* Transfer data ownership */
        another._p = nullptr;
        another._size = 0;
    }

private:
    T *_p;
    size_t _size;
}

您可以在此过程中看到,根本没有触及T类型的数据成员。

编辑:更特别是在C ++ 11标准中:§23.2.1。一般容器要求(4)有一个表包含一般容器实现的要求,其中包含以下要求:

X是元素的类型,u是标识符声明,rv是右值引用,aX类型的容器)

X u(rv)
X u = rv

C ++标准:对于除std::array之外的所有标准容器,这两个(移动构造函数)应具有恒定的时间复杂度。

因此很容易得出结论实现必须使用我上面提到的std::vector移动构造函数的方法,因为它不能调用单个元素的移动构造函数,否则时间复杂度将变为线性时间。

a = rv

C ++标准:a的所有现有元素要么移动分配给要么被销毁,要么等于rv在此分配之前的值。

这是移动分配操作员。这句话只说明a中的原始元素应该“妥善处理”(移动分配或销毁)。但这不是一个严格的要求。恕我直言的实施可以选择最合适的方式。

我还查看了Visual C ++ 2013中的代码,这是我找到的代码段(vector标题,从第836行开始):

/* Directly move, like code above */
void _Assign_rv(_Myt&& _Right, true_type)
{   // move from _Right, stealing its contents
    this->_Swap_all((_Myt&)_Right);
    this->_Myfirst = _Right._Myfirst;
    this->_Mylast = _Right._Mylast;
    this->_Myend = _Right._Myend;

    _Right._Myfirst = pointer();
    _Right._Mylast = pointer();
    _Right._Myend = pointer();
}

/* Both move assignment operator and move constructor will call this */
void _Assign_rv(_Myt&& _Right, false_type)
{    // move from _Right, possibly moving its contents
    if (get_allocator() == _Right.get_allocator())
        _Assign_rv(_STD forward<_Myt>(_Right), true_type());
    else
        _Construct(_STD make_move_iterator(_Right.begin()),
        _STD make_move_iterator(_Right.end()));
}

在此代码中,操作很明确:如果thisright操作数都具有相同的分配器,它将直接窃取内容而不对单个元素执行任何操作。但如果他们没有,那么将调用单个元素的移动操作。目前,其他答案适用(适用于std::shared_ptr个内容。)