Is it legal to call a method in a class with unique_ptr as an argument?

For example, if you have a declaration std::unique_ptr<A> a; Will the following problems occur?

 a->foo(std::move(a)); 

In my case, foo is a virtual function, so I cannot just pull it out of the class. If the above code is causing problems, then what is the alternative way to have the same effect?

+5
source share
2 answers

C ++ 11 and C ++ 14

It depends on the signature of foo :

  • If it is foo(std::unique_ptr<A> &&) , then the call is safe because the pointer retains the old value until foo starts execution. Regardless of whether or not foo changes, the pointer does not matter, because after evaluating the expression that calls the function, the statement from the execution of the called function is executed.
  • If it is foo(std::unique_ptr<A>) , then the call has undefined behavior. Although there is a rule that operands of an operator are evaluated before calculating the result of the operator (so you had to evaluate a before you could know whose foo to call and therefore call it), this is not enough here because there is no rule saying that the arguments functions are sequenced after the expression of the function name. Therefore, a can be moved from, and a.operator ->() call contains an attempt to dereference a null pointer.

C ++ 17

Since C ++ 17, it is safe. Several new sequence rules have been added, one of which exactly matches this case:

In an expression function expression, an expression that calls the function is sequenced before each argument expression and each default argument.

A source

Ah, well, I have to publish a safe version for pre-17 C ++. It is very simple, just add the desired sequence, for example. using two operators:

 auto aRaw = a.get(); aRaw->foo(std::move(a)); 
+5
source

I do not understand why this would not be legal.

According to this comment:

 a = a->imbue(std::move(a), op, std::move(b)); 

It looks like you want to use a consumption operation. That is, the function consumes its inputs (ownership is transferred to the function, and they are deleted upon exit), which happens.

One of the objects to be deleted is the one on which you call the member function, but although it seems that it can be difficult, this is certainly normal, because the object is still guaranteed to live during the call.

You are returning an object (presumably moving, since it is unique_ptr again), which is reassigned to the original name. Therefore, instead of c = a->imbue(a, op, b) it is a = a->imbue(a, op, b) .

Well, why not. This, by the way, is the same name, similar to the one you just deleted, but what exactly. The object is valid, and there is nothing that could reassign something else to the name. You reassign something else to the name when you write x = x + 1; and no one would mind it.

Something you may ultimately want to avoid (obvious, but maybe not so obvious?) imbue with the same Expression object in both places.

+1
source

Source: https://habr.com/ru/post/1273502/


All Articles