3

I'm bound to C++03 and I have a non-copyable object (e.g. holding a resource).

I need to use move-and-swap semantics to be able to do something similar and avoid copies:

MyClass returnMyClass(void)
{
    MyClass temp;
    // fill 'temp' members with actual data
    return temp;
}

int main(void)
{
    MyClass test;
    test = returnMyClass(); // need to avoid copies
}

Is it possible to respect all these requirements in C++03?

It is basically the same case of this, but for C++03.


To put the question in other words:

Given a non-copyable class MyClass, is it somehow possible in C++03 to do MyClass test = returnMyClass();?

I'm afraid the answer is simply no, but maybe I'm missing some trick.

gentooise
  • 416
  • 3
  • 8
  • its not clear why instead of `makeClass` you dont use a constructor – 463035818_is_not_an_ai Feb 19 '20 at 09:17
  • If you mean "can you return `test`, which is a variable of automatic storage duration, from the function using the syntax `return test` if the class is not copyable?" the answer is no. In C++03, that return statement implicitly calls the copy constructor and, if the compiler detects it cannot call that constructor, it is required to diagnose an error. The definition of `test()` in `main()` also requires an accessible copy constructor. That is true even if the compiler elides temporaries - which a C++03 compiler is not required to do. – Peter Feb 19 '20 at 09:22
  • Make your copy constructor private. Write a custom `move()` function and transfer the ownership of the underlying elements. – theWiseBro Feb 19 '20 at 09:28
  • MyClass test = makeClass() as in your example is an initialization. There is no copy. – mfnx Feb 19 '20 at 09:34
  • @Peter that's exactly what I wanted to ask, I edited the example code to remove ambiguities and clarify the problem. I did not mean to use a method instead of a constructor, and I did not intend an initialization. – gentooise Feb 19 '20 at 09:49
  • @mfnx - in C++03 the compiler is required to reject that initialisation if a copy constructor is inaccessible. – Peter Feb 19 '20 at 09:57
  • Would using pointers not solve your problems? – Aziuth Feb 19 '20 at 11:05
  • @Aziuth using pointers is exactly what I wanted to avoid. – gentooise Feb 19 '20 at 12:56

2 Answers2

2

There is no magic in move semantics. It's just another overload. The rvalue reference thing is a nice convenience that is not really essential.

template <class T>
struct rref { 
    rref (T& t) : t(t) {}
    T& t; 
};

template<class T>
rref<T> move(const T& t) {
   return rref<T>(const_cast<T&>(t));
}

// you now can do a "move ctor"
class Foo {
   Foo(rref<Foo>) { ... }
};

Now you also need NRVO to kick in for this to work. It is not guaranteed by the standard, but it is provided by pretty much every implementation. To ensure it really happens, you may declare but not define a copy ctor.

Full working demo

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • Yes, except that your proposal modifies the client of my class (i.e. the main function). I would like to do exactly `Foo foo = make_foo();`, not `Foo foo = move(make_foo());`. Sorry for not being clear on that. – gentooise Feb 19 '20 at 12:00
  • This may or may not be possible for initialisation, but most certainly not for assignment or passing functiin arguments. – n. m. could be an AI Feb 19 '20 at 16:28
  • Could that work if ``Foo`` provides a conversion operator to ``rref``? IINM, that's what the first move emulation proposals as well as Boost.Move really do. – Luis Machuca Feb 20 '20 at 14:29
  • 1
    @LuisMachuca it could work but I think implicit conversions are too dangerous. – n. m. could be an AI Feb 20 '20 at 15:06
0

If you can initialize your object test at declaration you will be able to avoid copying because copy elision will be performed.

class MyClass
{
  public:
    MyClass(){std::cout << "Default Constructor" << std::endl;}
    MyClass(const MyClass &){std::cout << "CPYConstructor" << std::endl;}
    ~MyClass() {std::cout << "Destructor" << std::endl;}

};


MyClass returnMyClass(void)
{
    MyClass temp;
    // fill 'temp' members with actual data
    return temp;
}

int main(void)
{
    MyClass test = returnMyClass(); // need to avoid copies
}

Output:

Default Constructor
Destructor
Ionut Alexandru
  • 680
  • 5
  • 17
  • The problem is not about copy elision, the problem is that a C++03 compiler still requires the copy ctor (`MyClass(const MyClass &)`), which I do **NOT** want to define because my class is non-copyable. – gentooise Feb 19 '20 at 12:03