boost::optional + boost::in_place
If copy constructor is dangerous, it is better to disable it completely.
Though most of compilers would elide copies in your case, some times it is possible to disable copy elision, for instance -fno-elide-constructors - and if code which "believes" in copy-elision would happen to run on such settings - there may be fireworks.
In C++98 you may use boost::optional + boost::in_place - there is no heap allocation, becuase boost::optional reserves enough place. And it is guaranteed that there will be no any copies.
live demo
#include <boost/utility/in_place_factory.hpp>
#include <boost/noncopyable.hpp>
#include <boost/optional.hpp>
#include <iostream>
#include <ostream>
using namespace boost;
using namespace std;
struct Foo: private noncopyable
{
explicit Foo(int i)
{
cout << "construction i=" << i << endl;
}
};
void make(optional<Foo> &foo)
{
foo = in_place(11);
}
int main()
{
optional<Foo> foo;
cout << "*" << endl;
make(foo);
cout << "!" << endl;
}
Output is:
*
construction i=11
!
This code does work on MSVC2005.
Boost.Move
Another option is to use move semantic emulation for C++98 - Boost.Move. Copies are disabled:
live demo
#include <boost/move/utility.hpp>
#include <iostream>
#include <ostream>
using namespace std;
class Movable
{
BOOST_MOVABLE_BUT_NOT_COPYABLE(Movable)
bool own_resource;
public:
Movable()
: own_resource(true)
{}
~Movable()
{
cout << (own_resource ? "owner" : "empty") << endl;
}
Movable(BOOST_RV_REF(Movable) x)
: own_resource(x.own_resource)
{
x.own_resource = false;
}
Movable& operator=(BOOST_RV_REF(Movable) x)
{
own_resource = x.own_resource;
x.own_resource = false;
return *this;
}
};
Movable make()
{
return Movable();
}
int main()
{
Movable m = make();
}
Output is:
empty
empty
owner
This code also does work on MSVC2005.
C++11
In C++11 use following approach:
live demo
struct Foo
{
Foo(const Foo &)=delete;
Foo(Foo &&)=delete;
Foo &operator=(const Foo&)=delete;
Foo &operator=(Foo &&)=delete;
Foo(int){}
};
Foo create()
{
//return Foo{0}; // ERROR: needs Foo(self &&)
return {0};
}
int main()
{
auto &&t=create();
}
Foo is created only once, it's copy and move constructor are deleted - it is guaranteed that there will be no any copies or moves.