How to avoid dangling reference with R-value - c++

Some discussion warns about dangling reference, with R-Value reference. I do not see any dangling reference in the following example as DTOR was called when main() terminates. Am I missing something?
class test_ctor
{
public:
explicit
test_ctor(int x = 1):_x(x)
{
std::cout << "CTOR: " << _x << "\n";
}
~test_ctor()
{
std::cout << "DTOR: " << _x << "\n";
}
test_ctor(test_ctor const & y) = default;
test_ctor(test_ctor && y) = default;
int _x;
};
test_ctor test_rvalue()
{
test_ctor test = test_ctor(2);
return test;
}
Now I can use the above code in two ways:
int main(int argc, const char * argv[]) {
auto test = test_rvalue();
std::cout << " test: " << test._x << " \n";
return 0;
}
Or
int main(int argc, const char * argv[]) {
auto && test = test_rvalue();
std::cout << " test: " << test._x << " \n";
return 0;
}
both case has the same output:
CTOR: 2
test: 2
DTOR: 2
Which means both are efficient ways to return object. Are there any side effects in r-value reference?

In c++11:
auto test = test_rvalue(); moves the return value of test_rvalue() into test. This move is then elided by every non-brain damaged compiler so it never happens. The move constructor still needs to exist, but is never called, and any side effects of moving do not occur.
auto&& test = test_rvalue(); binds an rvalue reference to the temporary returned by test_rvalue(). The temporaries lifetime is extended to match that of the reference.
In c++17:
auto test = test_rvalue(); the prvalue return value of test_rvalue() is used to directly construct the variable test. No move, elided or not, occurs.
The auto&& case remains unchanged from c++11.

Related

How to perfectly forward `*this` object inside member function

Is it possible to perfectly forward *this object inside member functions? If yes, then how can we do it? If no, then why not, and what alternatives do we have to achieve the same effect.
Please see the code snippet below to understand the question better.
class Experiment {
public:
double i, j;
Experiment(double p_i = 0, double p_j = 0) : i(p_i), j(p_j) {}
double sum() { return i + j + someConstant(); }
double someConstant() && { return 10; }
double someConstant() & { return 100; }
};
int main() {
Experiment E(3, 5);
std::cout << std::move(E).sum() << "\n"; // prints: 108
std::cout << E.sum() << "\n"; // prints: 108
}
This output seems expected if we consider that *this object inside the member function double sum() is always either an lvalue or xvalue (thus a glvalue) . Please confirm if this is true or not.
How can we perfectly forward *this object to the member function call someConstant() inside the double sum() member function?
I tried using std::forward as follows:
double sum() {
return i + j + std::forward<decltype(*this)>(*this).someConstant();
}
But this did not have any effect, and double someConstant() & overload is the one always being called.
This is not possible in C++11 without overloading sum for & and && qualifiers. (In which case you can determine the value category from the qualifier of the particular overload.)
*this is, just like the result of any indirection, a lvalue, and is also what an implicit member function call is called on.
This will be fixed in C++23 via introduction of an explicit object parameter for which usual forwarding can be applied: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0847r7.html
One would think that std::forward() would preserve lvalue references but it doesn't in non-template contexts, as the example below shows.
Both call_f()& and call_f()&& call f()&&. std::forward<Experiment>(*this) in a non-template function returns an rvalue reference regardless of the value category of the argument.
Note how this works differently from a template function, member or not (I made the member function static because it receives a "this reference" as an explicit parameter) . Both forward lvalue references "properly" (the last 4 calls).
#include<iostream>
#include<utility>
#include<string>
struct Experiment
{
public:
std::string f()&& { return "f()&&"; }
std::string f()& { return "f()&"; }
std::string call_f()&& { std::cout << "call_f()&& "; return std::forward<Experiment>(*this).f(); }
// I need this function because it is not a template function
std::string call_f()& { std::cout << "call_f()& "; return std::forward<Experiment>(*this).f(); }
template<class T = Experiment>
static std::string E_t_call_f(T&& t) { std::cout << "E_t_call_f(T&& t) "; return std::forward<T>(t).f(); }
};
template<class T>
std::string t_call_f(T&& t) { std::cout << "t_call_f(T&& t) "; return std::forward<T>(t).f(); }
int main()
{
Experiment E;
std::cout << "E.f(): " << E.f() << '\n';
std::cout << "move(E).f(): " << std::move(E).f() << '\n';
std::cout << '\n';
std::cout << "E.call_f(): " << E.call_f() << '\n';
std::cout << "move(E).call_f(): " << std::move(E).call_f() << '\n';
std::cout << '\n';
std::cout << "t_call_f(E): " << t_call_f(E) << '\n';
std::cout << "t_call_f(std::move(E)): " << t_call_f(std::move(E)) << '\n';
std::cout << '\n';
std::cout << "E::E_t_call_f(E): " << Experiment::E_t_call_f(E) << '\n';
std::cout << "E::E_t_call_f(std::move(E)): " << Experiment::E_t_call_f(std::move(E)) << '\n';
}
In the resulting output it is the third line that's surprising: The type of std::forward<Experiment>(*this) for an lvalue reference to *this is an rvalue reference.
E.f(): f()&
move(E).f(): f()&&
call_f()& E.call_f(): f()&&
call_f()&& move(E).call_f(): f()&&
t_call_f(T&& t) t_call_f(E): f()&
t_call_f(T&& t) t_call_f(std::move(E)): f()&&
E_t_call_f(T&& t) E::E_t_call_f(E): f()&
E_t_call_f(T&& t) E::E_t_call_f(std::move(E)): f()&&

C++ Destructor thru reference

I want to share with you a tiny problem that I'm not getting to work out, here is the code (it's for test only):
#include <windows.h>
#include <iostream>
#include <vector>
#include <string>
#include <utility>
#include <type_traits>
#include <sstream>
struct Procedure {
Procedure(HANDLE)
{ std::cout << "ctor w/connection: " << this << std::endl; }
~Procedure()
{ std::cout << "dtor: " << this << std::endl; }
Procedure(Procedure &&rhs) {
std::cout << "ctor w/move: " << this << std::endl;
this->m_Params = std::move(rhs.m_Params);
}
Procedure& operator= (Procedure &&rhs) {
std::cout << "operator= w/move: " << this << std::endl;
if (this != &rhs) this->m_Params = std::move(rhs.m_Params);
return *this;
}
Procedure& AppendParam(const std::string &str) {
std::cout << "appendparam: " << this << std::endl;
m_Params.push_back(str);
return *this;
}
void Execute( const std::string &str) {
std::stringstream ss;
ss << str << '(';
for (int i = 0, mx = m_Params.size(); i < mx; ++i) {
ss << '\'' << m_Params[i] << '\'';
if (i < mx - 1) ss << ',';
}
ss << ");";
std::cout << "calling: " << this << " : " << ss.str() << std::endl;
}
private:
Procedure(const Procedure &) = delete;
Procedure& operator=(const Procedure &) = delete;
std::vector<std::string> m_Params;
};
Procedure ProcedureCaller()
{ return Procedure(nullptr); }
int __cdecl main() {
std::cout << "test1---------------------" << std::endl; {
auto &proc = ProcedureCaller().AppendParam("param_1").AppendParam("param_2");
proc.Execute("sp_test");
}
std::cout << "test2--------------------" << std::endl; {
auto proc = ProcedureCaller();
proc.AppendParam("param_A").AppendParam("param_B");
proc.Execute("sp_test_2");
}
std::cout << "test3--------------------" << std::endl; {
ProcedureCaller().AppendParam("param_AA").AppendParam("param_BB").Execute("sp_test_2");
}
return 0;
}
And here is the result I'm getting:
test1---------------------
ctor w/connection: 00F8FC98
appendparam: 00F8FC98
appendparam: 00F8FC98
dtor: 00F8FC98
calling: 00F8FC98 : sp_test();
test2--------------------
ctor w/connection: 00F8FD70
appendparam: 00F8FD70
appendparam: 00F8FD70
calling: 00F8FD70 : sp_test_2('param_A','param_B');
dtor: 00F8FD70
test3--------------------
ctor w/connection: 004FFB20
appendparam: 004FFB20
appendparam: 004FFB20
calling: 004FFB20 : sp_test_2('param_AA','param_BB');
dtor: 004FFB20
I have a few questions:
1- Why dtor of "test1" is getting called before the end of its scope? I mean, the code hasn't even called the Execute method.
2- If dtor of "test1" is a temporal object, why I'm not seeing a log from the move ctor, or at least a compiler error because it's trying to use the deleted copy ctor?
3- What's the difference between "test1" and "test2", I want to be able to call the Execute whatever way I want.
4- What am I missing?
Thanks.
Here's a simpler version demonstrating the same problem:
struct X {
X() = default;
~X() { std::cout << "dtor\n"; }
X& self() { return *this; }
};
int main()
{
X& x = X().self();
std::cout << "here?\n";
}
This program prints dtor before it prints here. Why? The problem is, we have a temporary (X()) that does not get lifetime extended, so it gets destroyed at the end of the expression that contains it (which is X().self()). While you get a reference to it, it's not one of the magic references that does lifetime extension - what you get is just a reference to an object that's immediately going out of scope.
Lifetime extension only happens under very limited circumstances. The temporary has to be bound immediately to a reference, which can only happen for const references:
X const& x = X();
std::cout << "here\n";
Now this prints here before dtor.
Additionally, there is no transitive lifetime extension. Even if in the original example we did:
X const& x = X().self();
We'd still get a dangling reference.
In the "test1" case, the object referenced by proc is a temporary. It goes out of scope at the end of the full expression in which it was created, and proc is immediately left dangling. Note that no lifetime extension happens for two reasons: a) lifetime extension only happens with const lvalue-references and rvalue-references and b) lifetime extension only happens with prvalues, while the reference returned by AppendParam is an lvalue.
proc in the "test1" case is a reference, not an object. No move or copy happens because there is no object to be moved or copied to. A reference is bound to the temporary object returned by ProcedureCaller, and it goes out of scope at the next ;.
The difference between "test1" and "test2" is that proc is a reference in "test1" and an actual object in "test2". If you tried to make proc a reference in the "test2" case the compiler would complain. Only const lvalue-references and rvalue-references may be bound to a prvalue (such as the object returned from a function). The only reason it works in the "test1" case is that you've "laundered" the prvalue through a method that returns an lvalue-reference.

New pointer in class method must be casted into a reference

I have two classes, let's call them A and B
class A:
{
public:
//Some functions
A *getNewA() const;
private:
//some attributes
}
class B:
{
public:
//Some functions
private:
A &reftoA;
}
In the main code, I must generate a new A thanks to the A::getNewA() method. And this must go to B::reftoA, as written in class B.
Here is the A::getNewA() method :
A *A::getNewA()
{
A *newA = new A;
return newA;
}
OK. So now I call getNewA and want to store the results in reftoA, which is a reference to A. In a B function (which take a reference to A as parameter)
B::foo(A &paramA)
{
reftoA = *(paramA.getNewA());
}
I thought this should have been working, but it won't.
Because when dereferencing, reftoA will always take the this object and not the new allocated object.
Let's be clearer and let's modify the functions to output the results
A * A::getNewA()
{
A *newA = new A;
std::cout << "New pointer " << newA << std::endl;
std::cout << "this pointer" << this << std::endl;
return A;
}
void B::foo(A &paramA)
{
reftoA = *(paramA.getNewA());
std::cout << "new generated pointer " << &reftoA << std::endl;
}
Here is one of the output :
New pointer : 004FFAEC
this pointer: 0069D888
New generated pointer : 0069D888 //Expected : 004FFAEC
I can't get this "new generated pointer" to be the same than the new pointer the A::getNewA() returns after having allocated the memory. Of course, I guess there is some point with dereferencing the pointer to store it in a reference.
I know reference are used with existing object. Maybe the new object A::getNewA() should allocate memory for won't work as I expected.
I could use pointer instead reference in B::foo(), I know, but I can't
I think I am misunderstanding something about refrence and pointer, but I don't know what.
Any help greatly appreciated
The problem is that you can not reassign a reference. You can change only the value of the referenced object.
So you have to initialize the reference in the initializer list of the constructor of the class B.
Take into account that there is a typo in your code snippet
A*A::getNewA()
{
A *newA = new A;
std::cout << "New pointer " << newA << std::endl;
std::cout << "this pointer" << this << std::endl;
return A;
^^^^^^^^^
}
I think you mean
A*A::getNewA() const
^^^^^
{
A *newA = new A;
std::cout << "New pointer " << newA << std::endl;
std::cout << "this pointer" << this << std::endl;
return newA;
^^^^^^^^^^^
}
Always try to provide a verifiable complete example.
Here is a demonstrative program
#include <iostream>
class A
{
public :
//Some functions
A* getNewA() const
{
A *newA = new A;
std::cout << "New pointer " << newA << std::endl;
std::cout << "this pointer" << this << std::endl;
return newA;
}
private :
//some attributes
};
class B
{
public :
B( const A& a ) : reftoA( *a.getNewA() )
{
std::cout << "&reftoA " << &reftoA << std::endl;
}
private :
A& reftoA;
};
int main()
{
A a;
B b( a );
return 0;
}
Its output is
New pointer 0x2b392afbec20
this pointer0x7ffd287ad0af
&reftoA 0x2b392afbec20
As you can see the values of the New pointer and &reftoA are equal each other.
To make it more clear consider a very simple example
#include <iostream>
int main()
{
int x = 10;
int y = 20;
int &r = x;
r = y;
std::cout << "x = " << x << std::endl;
std::cout << "y = " << y << std::endl;
std::cout << "r = " << r << std::endl;
std::cout << std::endl;
std::cout << "&x = " << &x << std::endl;
std::cout << "&y = " << &y << std::endl;
std::cout << "&r = " << &r << std::endl;
return 0;
}
The program output is
x = 20
y = 20
r = 20
&x = 0x7ffd88ad47a8
&y = 0x7ffd88ad47ac
&r = 0x7ffd88ad47a8
This statement
r = y;
did not force the reference to refer the object y. It just reassigned the value of the referenced object x.
References have to be initialized when they are created.
Yes, you are misunderstanding something.
getNewA() is returning a pointer. it's not a smart pointer, you want to look into those and that's all I'll say on the matter.
on returning a pointer, you must keep a reference to this pointer else you will be unable to delete it and you'll get a memory leak. Thus you MUST have somewhere A* a = A::getNewA() and then later, when you no longer need it delete a;
Where you need to pass a reference to A, you can do foo(*a) which will dereference the pointer and pass a reference to the object it's pointing to.
But in summary, for all new code, smart pointers; there's no excuse to not use them.
Side note: Your code example had a few other issues; such as getNewA wasn't static; I'm going to take the code as a working example of your understanding, and not a working example.
Edit: On re-reading your example, the getNewA is intentionally non-static. I think this question is actually an XY problem (ie you're asking a question you've forced yourself into but isn't your actual problem); but I hope this addresses your misunderstanding of pointers and references.
You are not returning the pointer in the getNewA-Method
A* A::getNewA()
{
A *newA = new A;
return A; // you are returning A and not newA
}
And if you want to reassign the reference to a you can use a std::reference_wrapper
class B :
{
public :
void foo(A& paramA) {
reftoA = *(paramA.getNewA());
}
private :
std::reference_wrapper<A> reftoA;
}

When move semantics works with std::move?

How does move semantics work in this example:
struct test {
int ii[10];
int i;
};
test f() {
test a;
std::cout << "[1] " << &a << std::endl;
return a;
}
int main()
{
test x (f());
std::cout << "[2] " << &x << std::endl;
test x1 (std::move(x));
std::cout << "[3] " << &x1;
}
Output:
[1] 0x7fff50ac70c0
[2] 0x7fff50ac70c0
[3] 0x7fff50ac70f0
Why x was constructed using return value from f(), but x1 got different address than x?
Edit
struct test {
std::string s;
}
[...]
std::cout << (*void)&x.s[0];
I think I've understood eventually. Now addresses are the same.
This doesn't really have anything to do with move semantics. a and x have the same memory address because the copy is elided, so the return of f is allocated directly at the call site. x1 does not have the same address as x because it is a separate object, and separate objects cannot have the same address. Moving doesn't change the address, it allows the guts of your object to be ripped out and sellotaped into the moved-to object.

rvalue function overloading

I want to overload a function so that it manipulates its argument in some way and then returns a reference to the argument – but if the argument is not mutable, then it should return a manipulated copy of the argument instead.
After messing around with it for ages, here's what I've come up with.
using namespace std;
string& foo(string &in)
{
in.insert(0, "hello ");
return in;
}
string foo(string &&in)
{
return move(foo(in));
}
string foo(const string& in)
{
return foo(string(in));
}
This code seem to work correctly, but I'm interested to hear if anyone can think of a better way to do it.
Here's a test program:
int main(void)
{
string var = "world";
const string var2 = "const world";
cout << foo(var) << endl;
cout << var << endl;
cout << foo(var2) << endl;
cout << var2 << endl;
cout << foo(var + " and " + var2) << endl;
return 0;
}
The correct output is
hello world
hello world
hello const world
const world
hello hello world and const world
I figure it would be slightly neater if I could do this:
string& foo(string &in)
{
in.insert(0, "hello ");
return in;
}
string foo(string in)
{
return move(foo(in));
}
Of course, that doesn't work because most function calls to foo would be ambiguous – including the call in foo itself! But if I could somehow tell the compiler to prioritize the first one...
As I said, the code I posted works correctly. The main thing I don't like about it is the repetitive extra code. If I had a bunch of functions like that it would become quite a mess, and most of it would be very repetitive. So as a second part to my question: can anyone think of a way to automatically generate the code for the second and third foo functions? eg
// implementation of magic_function_overload_generator
// ???
string& foo(string &in);
magic_function_overload_generator<foo>;
string& bar(string &in);
magic_function_overload_generator<bar>;
// etc
I would get rid of the references all together and just write one function that passes and returns by value:
std::string foo(std::string in)
{
in.insert(0, "hello ");
return in;
}
If you pass an lvalue, the input string will be copied. If you pass an rvalue, it will be moved.
When leaving the function, named return value optimization will probably kick in, so the return is basically a no-op. If the compiler decides against that, the result will be moved (even though in is an lvalue).
The good thing about rvalue references is that you have to think less about where to put references in user code to gain efficiency. With movable types, pass-by-value is practically as efficient as it gets.
The whole question is why do you want to have such overloads? All these overloads specify one interface: foo(x). But x parameter may be input or input/output parameter depending on its type. It is very, very error-prone. A user shall do some additional job to make sure that its variable won't be mutated. Never do that in production code.
I would agree with such overloads:
string foo(string &&in);
string foo(const string& in);
Input parameter is never changed if it is not a temporary and, at the same time, you reuse temporary objects. It seems quite reasonable.
But, why do you want to generate a lot of such overloads? && overload is for optimization. I would say very delicate optimization. Are you sure you need it in lots of places?
Anyway, if you really want to generate C++ code, templates are not a really good choice. I would use some external tool for it. Personally, I prefer Cog.
What about following simple approach ?
string& foo (string &change) // this accepts mutable string
{
change = string("hello ") + change;
return change;
}
string foo (const string &unchange) // this accepts not mutable string
{
return string("hello ") + unchange;
}
See it's output here.
In the same vein as #iammilind's answer, but sans duplication:
#include <iostream>
using namespace std;
string foo(const string &unchange) {
return string("hello ") + unchange;
}
string& foo(string &change) {
return change = foo(static_cast<const string&>(foo));
}
int main(int argc, char** argv) {
string a = "world";
const string b = "immutable world";
cout << foo(a) << '\n' << foo(b) << '\n';
cout << foo(a) << '\n' << foo(b) << '\n';
}
NB: You could also use const_cast here to add the const qualification.
If you're not worried about efficiency, you can do pass by value or pass by const reference and do a copy and be done with it.
However, if you are worried about efficiency, I don't think the pass by value suggestion in this reply is the best approach. This is because I think it results in extra copies/moves, as NRVO only seems to work with local variables, not parameters. I think the way that avoids moves/copies in C++0x is the dual overloads, as illustrated by the following code:
#include <iostream>
struct A
{
A() : i(0) {}
A(const A& x) : i(x.i) { std::cout << "Copy" << std::endl; }
A(A&& x) : i(x.i) { std::cout << "Move" << std::endl; }
void inc() { ++i; }
int i;
};
A f1(const A& x2) { A x = x2; x.inc(); return x; }
A&& f1(A&& x) { x.inc(); return std::move(x); }
A f2(A x) { x.inc(); return std::move(x); }
int main()
{
A x;
std::cout << "A a1 = f1(x);" << std::endl;
A a1 = f1(x);
std::cout << "A a2 = f1(A());" << std::endl;
A a2 = f1(A());
std::cout << "A b1 = f2(x);" << std::endl;
A b1 = f2(x);
std::cout << "A b2 = f2(A());" << std::endl;
A b2 = f2(A());
std::cout << std::endl;
std::cout << "A a3 = f1(f1(x));" << std::endl;
A a3 = f1(f1(x));
std::cout << "A a4 = f1(f1(A()));" << std::endl;
A a4 = f1(f1(A()));
std::cout << "A b3 = f2(f2(x));" << std::endl;
A b3 = f2(f2(x));
std::cout << "A b4 = f2(f2(A()));" << std::endl;
A b4 = f2(f2(A()));
std::cout << std::endl;
std::cout << "A a5 = f1(f1(f1(x)));" << std::endl;
A a5 = f1(f1(f1(x)));
std::cout << "A a6 = f1(f1(f1(A())));" << std::endl;
A a6 = f1(f1(f1(A())));
std::cout << "A b5 = f2(f2(f2(x)));" << std::endl;
A b5 = f2(f2(f2(x)));
std::cout << "A b6 = f2(f2(f2(A())));" << std::endl;
A b6 = f2(f2(f2(A())));
}
Which produces the following results:
A a1 = f1(x);
Copy
A a2 = f1(A());
Move
A b1 = f2(x);
Copy
Move
A b2 = f2(A());
Move
A a3 = f1(f1(x));
Copy
Move
A a4 = f1(f1(A()));
Move
A b3 = f2(f2(x));
Copy
Move
Move
A b4 = f2(f2(A()));
Move
Move
A a5 = f1(f1(f1(x)));
Copy
Move
A a6 = f1(f1(f1(A())));
Move
A b5 = f2(f2(f2(x)));
Copy
Move
Move
Move
A b6 = f2(f2(f2(A())));
Move
Move
Move
You might be able to do some template tricks to avoid writing multiple overloads, for example:
template <class T>
param_return_type<T&&>::type f3(T&& y, typename std::enable_if<...>::type* dummy = 0 )
{
typedef return_t param_return_type<T&&>::type;
return_t x = static_cast<return_t>(y);
x.inc();
return static_cast<return_t>(x);
}
Where param_return_type<T>::type is T when passed (const) T&, and T&& when passed T&&. std::enable_if<...> you can use if you only want this template to take particular parameters.
I wasn't sure how to write a definition of param_return_type<T>::type, as it seems there is no std::remove_lvalue_reference. If anyone knows how to, feel free to edit/add to my post.