is it possible to restrict class instances to be used only as rvalues (e.g. temporaries)?
for example, I have class Wrapper
whose constructor takes A const&
and saves this reference in its member. It's a dangerous because lifetime of Wrapper
instance cannot be longer than lifetime of A
instance, but it's fine if Wrapper
is temporary
.
I don't think it would be safe:
const A &a = YourClass( tmp );
YourClass
in this case is the class you're looking for which only allow temporary instances, tmp
is the temporary value you pass to the constructor.
It's possible (ie: safe, defined behavior) to have a constant reference to a temporary (ie: a
), but the temporary itself (such instance of YourClass
) has got a reference to tmp
which is no longer valid after that expression is evaluated.
I think that even wanting to do this is a sign of a really bad design.
However, you could make all constructors private and make a friend function that returns an rvalue. That should do the trick.
Not exactly the answer you are looking for, but have you thought about weak pointers? (for example, boost::weak_ptr
). In this case, the original A
would be held in a shared_ptr
and the Wrapper
constructor accepts a weak_ptr
. The neat thing with this approach is that, before each usage of the weak_ptr
, you can attempt to lock()
which will give you a shared_ptr
- if that fails, you know that A
is gone and Wrapper
cannot function... But it's handled cleanly...
This might do the job unless your class has public data members.
Basically, the idea is not to restrict the construction of the wrapper but to make sure that instances can be used (just like you said) only as long as they are temporary values. One can achieve this by overloading all methods and deleting (or making them private) those that refer to const&.
Here's a simple example:
class Wrapper
{
public:
Wrapper() = default;
Wrapper(const std::string& name) : name(name) {}
void process() && { std::cout << "Greetings from " << name << std::endl; }
// Only temporary instances of this class are allowed!
void process() const & = delete;
private:
std::string name;
};
And some use cases:
Wrapper("John").process(); // intended use case
Wrapper j; // create whatever you want
j.process(); // error C2280: 'void Wrapper::process(void) const &': attempting to reference a deleted function
std::move(j).process(); // this is still possible
const Wrapper& t = Wrapper(); // bind the temporary to a const reference - not a problem because ...
t.process(); // error C2280: 'void Wrapper::process(void) const &': attempting to reference a deleted function
The obvious disadvantages are:
A similar thing has been done in the standard. The make routines for std::reference_wrapper do not accept temporaries.
Note that they considered another subtlety: the overload uses const T&& instead of T&&. This can be important in our case as well. For example, if your wrapper is deliberately designed to be noncopyable and you use make routines such as
const Wrapper make_wrapper();
instead of
Wrapper make_wrapper();
In this case, you might want to replace
void process() &&;
by
void process() const &&;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With