2015-01-07 80 views
7

我的问题涉及如何返回没有拷贝构造函数的对象。举个例子,我们假设我有一些bigResource位于堆中,我们假设我使用unique_ptr来跟踪它。现在假设我将这种资源的所有权交给毛虫。然后我有一个CaterpillarWithBigResource。现在在某个时候,这个CaterpillarWithBigResource将变为ButterflyWithBigResource,因此Caterpillar对象将不得不将所有权转移给Butterfly对象。如何返回没有拷贝构造函数的对象

我写了下面的代码的情况型号:

#include <cstdlib> 
#include <iostream> 
#include <memory> 

class ButterflyWithBigResource { 
public: 

    // If I uncomment just this line, I get an error 
    // ButterflyWithBigResource(const ButterflyWithBigResource& other) = default; 

    // If I uncomment just this line, I get an error 
    // ButterflyWithBigResource(const ButterflyWithBigResource& other) = delete; 

    // With both above lines commented out, I get no errors, and the program runs fine. 

    ButterflyWithBigResource(std::unique_ptr<int>&& bigResource) : 
    bigResource(std::move(bigResource)) { 

    } 

    const int& getResource() { 
     return *bigResource; 
    } 

private: 
    std::unique_ptr<int> bigResource; 
}; 

class CaterpillarWithBigResource { 
public: 

    CaterpillarWithBigResource(int bigResource) : 
    bigResource(new int(bigResource)) { 

    } 

    ButterflyWithBigResource toButterfly() && { 
     return ButterflyWithBigResource(std::move(bigResource)); 
    } 
private: 
    std::unique_ptr<int> bigResource; 
}; 

/* 
* 
*/ 
int main(int argc, char** argv) { 
    CaterpillarWithBigResource caterpillarWithBigResource(5); 
    ButterflyWithBigResource butterflyWithBigResource(std::move(caterpillarWithBigResource).toButterfly()); 
    std::cout << butterflyWithBigResource.getResource() << std::endl; 
    return 0; 
} 

注意,无论是Caterpillar还是Butterfly有默认的拷贝构造函数,因为他们每个人都有一个unique_ptr。然而,我不希望这是问题,所以只有移动构造函数才是必要的。毕竟,我只是将所有权从Caterpillar转移到Butterfly

事实上,当我使用g++版本4.8.2编译程序g++ -c -g -std=c++11 -MMD -MP -MF它工作得很好。

但现在奇怪的是,如果我要提醒的是,Butterfly的拷贝构造函数被删除编译器通过将线ButterflyWithBigResource(const ButterflyWithBigResource& other) = delete;,程序不再编译,编译器抱怨的拷贝构造函数被删除,这样我可以在toButterfly方法中不返回Butterfly

如果我然后试着告诉它,一切正常,而不是行ButterflyWithBigResource(const ButterflyWithBigResource& other) = default;,我再次得到相同的错误。

我希望发生的是在toButterfly方法构建的Butterfly被转移到toButterfly的返回地址,再后来用作Butterfly的说法“在main()构建butterflyWithBigResource时的举动的构造。有没有办法做到这一点?

+0

BTW,返回,没有拷贝构造一个对象,你会使用复印通list-initialization:'return {std :: move(bigRes我们)}' – 0x499602D2

回答

7

当您注释掉明确defaultdelete拷贝构造函数的行时,编译器可以自由为您隐式生成移动构造函数(并移动赋值运算符)。

通过明确default ing或delete复制构造函数,可以禁止隐式生成移动构造函数。

从N3337,§12.8/ 9[class.copy]

如果一个类X的定义不明确宣布此举的构造函数,一个将被隐式声明为默认,如果和只有当
- X没有一个用户声明的拷贝构造函数,
- ...

不再生成移动构造函数时,必须复制toButterfly()的返回值,但无论您是否默认或删除了复制构造函数,都会失败。

如果您使用default复制构造函数,编译器由于存在unique_ptr数据成员(不可复制)而无法生成默认的复制构造函数实现。

当您复制构造函数,如果它通过重载决议被选中,这是一个错误。


你不应该直接删除,因为拷贝构造函数,如上所述,该unique_ptr数据成员的存在暗示其删除,但如果你想这样做,那么你还需要明确默认情况下,移动构造函数(和移动赋值运算符太,如果你想移动分配工作)

ButterflyWithBigResource(ButterflyWithBigResource&&) = default; 
ButterflyWithBigResource& operator=(ButterflyWithBigResource&&) = default; 

Live demo

+0

哦,那很简单。 –

+0

修复了它。在我的真实代码中,我有'virtual〜C()= default;'。 –

+1

@NowIGetToLearnWhatAHeadIs * - 'X'没有用户声明的析构函数*是上面列表中的第四个项目符号:) – Praetorian