11

Just a question. Looking at C++ Boost libraries (in particular boost::thread class) I ended up thinking: "how is it possible to create a class defining objects that cannot be copied but that can be returned from a function?"

Well consider this example, the boost::thread class has the characteristics I mentioned before, so it is possible to do this:

boost::thread make_thread();

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

Well this means that the object boost::thread cannot be copied, but returned from a function, this is possible. How is this possible????

I suppose that a copy constructor must not be provided, but how to deal with returning from a function? doesn't it need to use a copy constructor???

Thankyou

Andry
  • 493
  • 1
  • 5
  • 6

2 Answers2

6

This is possible starting with C++11, which provides move semantics via rvalue references. Using this you can implement moving and/or copying separatedly:

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);
    }

    // ...
};

Copying and moving can be forbidden separately, so you can setup classes that can be moved, but not copied.

Of course, there are a few magical tricks that let you do this even when your compiler doesn't yet support move semantics (std::auto_ptr, after all moves instead of copying when assigned to), so this might work for boost::thread even in the absence of move semantics.

Kai Ninomiya
  • 156
  • 2
  • 6
sbi
  • 219,715
  • 46
  • 258
  • 445
  • What's c++1x? I can see c1x and c++0x on the internet, but not c++1x. Is it shorthand for both of them? – Alex Brown Nov 23 '10 at 19:57
  • 1
    @Alex - it's smart-ass speak for the fact that it's already 2010 and they haven't released. There's a smarter-ass counter: 0x is hexidecimal. – Edward Strange Nov 23 '10 at 19:59
  • @Alex: It used to be named C++0x, because it was expected _before_ 2010, but this didn't work out. Many still stick to "C++0x", even though it will likely end up as C++11 or C++12. – sbi Nov 23 '10 at 19:59
  • @Noah: Then it would have to be C++0xX, though. `:)` – sbi Nov 23 '10 at 20:04
  • @sbi: not if x in `C++0x` is one of `[0-9A-F]`, or, hexadecimal. aargh, I have no sense of humor :P – rubenvb Nov 23 '10 at 20:45
  • 2
    @sbi: I think most committee members and compiler implementers still refer to it as C++0x, so I think it'd be more fair to say that it *is* named C++0x because it was expected before 2010. But that's just nitpicking. :) – jalf Nov 23 '10 at 21:02
  • @rubenvb: In C++, a hex number literal starts with `0x`, after that come the actual digits. `:)` – sbi Nov 23 '10 at 21:26
  • To really nitpick: it's *named* "ISO/IEC 14882: Programming Language C++ current draft", which at the moment is n3126 or something. For obvious reasons, it needs a nickname, which is most commonly C++0x, despite a lot of joking about C++1x when it became clear there would be no standard by the end of 2009. – Steve Jessop Nov 23 '10 at 22:46
  • @Steve: I wasn't revering to the "current draft", but the standard _as we will have it_ in 2011 or 2012, which would make it either "C++11" or "C++12". Since I didn't want to guess on the year, I replaced the last digit by an 'x'. `:)` – sbi Nov 24 '10 at 10:51
  • 1
    @sbi: Ah, right. In that case I correct my previous comment: its name will be "ISO/IEC 14882: Programming Language C++", the same as C++98 and C++03. Which can't possibly cause any confusion :-) – Steve Jessop Nov 24 '10 at 11:31
3

This is an advanced topic of C++ if you want to do this in C++03. See Howard Hinnants Unique_ptr C++03 emulation for an example of that.

It basically works by abusing several subtle rules in C++ overload resolution, in particular the rule that non-const references cannot bind to rvalue temporaries and that non-const conversion functions can still be called on non-const temporaries.

You can also use the auto_ptr technique as employed by C++03, which however is seen as broken by several groups because auto_ptr lets you copy variables, but steal resources from the copied-from object (other groups have other opinions about this).

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212