2013-11-22 45 views
3

我注意到,当包含类型包含unique_ptr时,不可能删除矢量的元素。如何在包含对象包含unique_ptr时删除矢量的元素?

例如这个类:

class Bar 
    { 
     std::unique_ptr<int> pointerTest; 

     Bar(Bar &bar) {}; 

    public: 
     Bar() { pointerTest = std::unique_ptr<int>(new int); } 
     Bar(Bar &&bar) { this->pointerTest = move(bar.pointerTest); } 

     void testFunc() { pointerTest.release(); } 
    }; 

这不会与这种用法工作:

int main() 
    { 
     vector<Bar> test123; 

     Bar foo; 
     test123.push_back(move(foo)); 
     test123.erase(test123.begin()); 
    } 

    //Error 1 error C2280: 'std::unique_ptr<int,std::default_delete<_Ty>> &std::unique_ptr<_Ty,std::default_delete<_Ty>>::operator =(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' : attempting to reference a deleted function c:\program files (x86)\microsoft visual studio 12.0\vc\include\xmemory0 611 1 testing 

的代码将工作时,你只调用对象的方法,而不是擦除:

for (auto &item : test123) 
    item.testFunc(); 

为什么我不能在矢量上使用擦除,我该如何解决这个问题?

+2

FWIW,你的代码在g ++ 4.6下编译。 – user4815162342

+0

我可以通过删除不必要的移动构造函数和奇怪的副本构造函数来解决GCC 4.8上的问题。我不知道问题到底是什么,或者是否会为您的编译器解决问题。 –

+0

奇怪的是,我无法在visual studio 2013上编译此文件,无论是否带有复制和移动构造函数。 @Mike Seymour关于这些构造函数的连线是什么? – Dagob

回答

3

问题是您的班级没有正确遵守三/五的规则。您可以定义一个副本并移动构造函数,但不能移动赋值运算符。这意味着不会生成移动赋值运算符,并且在分配时始终使用默认的复制赋值运算符。但是,由于您的课程拥有不可复制的成员,因此默认的复制分配操作符被定义为已删除,因此您在使用时会出错。

并且它被调用,因为从矢量中移除元素会导致矢量的所有后续元素的移位(即赋值)。这通常是一个移动赋值,但是由于在你的类中没有定义(而不是自动生成),复制赋值被调用 - 并且失败。

我看到你使用的是Visual Studio,所以移动构造/移动赋值操作符不会自动生成(VS不支持这部分标准)。因此,要以VS兼容的方式解决此问题,请定义一个移动赋值运算符。在你处理拷贝构造函数的时候删除拷贝构造函数可能是一个好主意 - 这个类看起来像是一个非拷贝类的主要例子。

1

从克++ 4.8.1该错误消息是很清楚:

garbage.cpp:9:11:注意: '酒吧&酒吧::运算符=(const的酒吧&)' 被 隐式声明如删除,因为“酒吧”宣称此举 构造函数或移动赋值操作符

通过增加移动运营商的问题就解决了:

class Bar 
{ 
     std::unique_ptr<int> pointerTest; 

     Bar(const Bar &); 

public: 
     Bar() { pointerTest = std::unique_ptr<int>(new int); } 
     Bar(Bar &&bar) : pointerTest(move(bar.pointerTest)) {} 
     Bar& operator=(Bar&& bar){ pointerTest = std::move(bar.pointerTest); return *this;} 

     void testFunc() { pointerTest.release(); } 
};