在C++中创建不可复制但可移动的对象

11

只是一个问题。看着C++ Boost库(特别是boost::thread类),我开始思考:“如何创建一个定义了不能复制的对象但可以从函数返回的类?”

那么考虑这个例子,boost::thread类具有我之前提到的特性,因此可以这样做:

boost::thread make_thread();

void f()
{
    boost::thread some_thread=make_thread();
    some_thread.join();
}

这意味着对象boost::thread不能被复制,但可以从函数中返回。

这是如何可能的???

我认为不应该提供一个拷贝构造函数,但如果要从函数中返回,该怎么处理?难道不需要使用拷贝构造函数吗?

谢谢。

2个回答

6
这是可能的,从C++11开始,它通过右值引用提供了移动语义。使用这个特性,你可以分别实现移动和/或复制操作。
class my_class {
  private:
    data_t* data_;
  public:
    my_class(const my_class& rhs)      // copy constructor
     : data_(rhs.data_.clone())
    {}
    my_class(my_class&& rhs)           // move constructor
     : data_(rhs.data_)
    {
      rhs.data_ = NULL;
    }
    ~my_class() {delete data_;}        // noop if data_==NULL

    my_class& operator=(my_class rhs)  // copy assignment
    {
      this->swap(rhs);
    }
    my_class& operator=(my_class&& rhs)// move assignment
    {
      this->swap(rhs);
    }

    // ...
};

复制和移动可以分别禁止,因此您可以设置只能移动而不能复制的类。
当然,即使您的编译器尚不支持移动语义(例如,std::auto_ptr在赋值时会移动而不是复制),仍然有一些神奇的技巧可以让您实现这一点,所以即使没有移动语义,这对于boost::thread也可能起作用。

C++1x是什么?我在互联网上看到了c1x和c++0x,但没有看到c++1x。它是两者的简称吗? - Alex Brown
1
@Alex - 这是一种聪明的说法,因为现在已经是2010年了,而他们还没有发布。还有一种更聪明的反驳方式:0x是十六进制。 - Edward Strange
@Alex:它曾被命名为C++0x,因为预计会在2010年之前发布,但这并没有实现。许多人仍然坚持使用“C++0x”,尽管它最终可能会成为C++11或C++12。 - sbi
2
@sbi:我认为大多数委员会成员和编译器实现者仍然将其称为C++0x,因此我认为更公平的说法是它被命名为C++0x,因为它在2010年之前就有了预期。但这只是纠缠细节而已。 :) - jalf
1
@sbi:啊,对了。那样的话,我要更正之前的评论:它的名称将是“ISO/IEC 14882: 编程语言 C++”,与 C++98 和 C++03 相同。这绝对不会引起任何混淆 :-) - Steve Jessop
显示剩余5条评论

3
这是一篇关于C++高级话题的文章,如果你想在C++03中实现此功能,请参考Howard Hinnants Unique_ptr C++03 emulation示例。
它基本上通过滥用C++重载分辨率中的几个微妙规则来实现,特别是非const引用不能绑定到rvalue临时对象的规则,以及非const转换函数仍然可以在非const临时对象上调用的规则。
你也可以使用C++03中使用的auto_ptr技术,但由于auto_ptr允许您复制变量,但从被复制的对象中窃取资源,因此被一些团体视为有缺陷(其他团体对此有不同的看法)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接