Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

is it possible to restrict class instances to be used only as temporaries?

Tags:

c++

c++11

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.

like image 998
Andriy Tylychko Avatar asked Jan 31 '11 12:01

Andriy Tylychko


4 Answers

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.

like image 68
peoro Avatar answered Sep 30 '22 17:09

peoro


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.

like image 34
Puppy Avatar answered Sep 30 '22 19:09

Puppy


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...

like image 42
Nim Avatar answered Sep 30 '22 18:09

Nim


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:

  • You have to overload every public member function.
  • The error message is delayed and not very informative.

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 &&;
like image 24
thebrandre Avatar answered Sep 30 '22 18:09

thebrandre