C++: move / forwarding / rvalue delegation shenanigans [duplicate] - c++

This question already has answers here:
Why do you use std::move when you have && in C++11? [duplicate]
(4 answers)
Closed 7 years ago.
Try running this test program :
#include <iostream>
class A {
public:
A() { std::cout << "empty constructor" << std::endl; }
A(const A &a) { std::cout << "copy constructor" << std::endl; }
A(A &&a) { std::cout << "move constructor" << std::endl; }
~A() { std::cout << "destructor" << std::endl; }
A &operator=(const A &o) { std::cout << "copy assignment" << std::endl; return *this; }
A &operator=(A &&o) { std::cout << "move assignment" << std::endl; return *this; }
};
A outside;
template <typename U>
void bar(U &&a) {
outside = std::forward<U>(a);
}
void foo(A &&a) {
bar(a);
}
int main(int argc, char *argv[]) {
foo(A());
return 0;
}
On my compiler, I think GCC 4.4.1, the output is:
empty constructor
empty constructor
copy assignment // what??
destructor
destructor
In my opinion the third line is strange. Why is outside copying a in bar instead of moving it? In other words,hy does foo use the bar(A &a) instantiation of bar instead of bar(A &&a)?
I should mention that this problem is easily fixable by changing foo to
template <typename U>
void foo(U &&a) {
bar(std::forward<U>(a));
}
whereupon the move assignment operator is used instead.
In my code I have a lot of delegation methods and I'd hate to have to stick them all in a .h file and make templates for them. Is there another way of telling the compiler or making it understand that a is used as an rvalue in foo?
EDIT: A few people pointed out this change:
void foo(U &&a) {
bar(std::move(a));
}
I was too slow to indicate that I want foo to be able to accept both:
int main(int argc, char *argv[]) {
foo(A());
return 0;
}
and
int main(int argc, char *argv[]) {
A a;
foo(a);
return 0;
}
The suggested code will incorrectly steal, in the second case, a's resources in main where it should be used as a reference.

Inside your foo function it should be:
bar(std::move(a)) because the parameter a is at that point an lvalue.

Related

Why return by reference disables NRVO [duplicate]

This question already has answers here:
Returning a reference to a local variable in C++
(3 answers)
c++ missing construction and destruction of an object
(2 answers)
Does returning a local variable return a copy and destroy the original(nrvo)?
(1 answer)
Shouldn't there be a copy ctor invocation here? Elision disabled (no named return value optimization)
(1 answer)
Closed 5 months ago.
I was testing out the Return Value Optimizations in C++ Visual Studio 2022. I was surprised that the following program needed to call the copy constructor:
#include <iostream>
class A {
public:
A() { std::cout << "Constructor calling" << std::endl; }
A(A& a) { std::cout << "Copy Constructor calling" << std::endl; }
A(const A& a) { std::cout << "const Copy Constructor calling" << std::endl; }
};
A& getA() { A a; return a; }
int main() {
A a = getA();
return 0;
}
This outputs Constructor Calling\nCopy Constructor Calling, which means it did not get optimized with NRVO. Yet when I change the program to the following (just removed the return by reference on getA()):
#include <iostream>
class A {
public:
A() { std::cout << "Constructor calling" << std::endl; }
A(A& a) { std::cout << "Copy Constructor calling" << std::endl; }
A(const A& a) { std::cout << "const Copy Constructor calling" << std::endl; }
};
A getA() { A a; return a; }
int main() {
A a = getA();
return 0;
}
Now we get the output as just Constructor calling and no calls to the copy constructor. Why does it not get optimized when I am returning by reference?

c++ passing an object as function parameter to a function expecting an std::optional

I have a function func(std::optional<A>& a) and I want to call it using an instance of A like in this code:
#include <optional>
#include <iostream>
class A
{
public:
explicit A(int a) : m_a(a)
{}
~A() = default;
int get() { return m_a; }
A(const A&) = delete;
A(A&&) = delete;
A& operator=(const A&) = delete;
A& operator=(A&&) = delete;
private:
int m_a;
};
void func(std::optional<A>& a)
{
if (a.has_value()) {
std::cout << a->get() << std::endl;
} else {
std::cout << "no value" << std::endl;
}
}
int main() {
A a(5);
func(a);
}
As you can see, A does not allow for any copy or move operators. When I run this code I get
<source>:34:10: error: invalid initialization of reference of type 'std::optional<A>&' from
expression of type 'A'
My question is how can I pass a to func() and make the std::optional reference my object?
If that's not possible, I would still like to have a way to pass a to func() not using c-style pointers (func(A* a) for example)
If another layer of indirection is not a problem you can use a std::optional<std::reference_wrapper<A>> :
#include <functional>
//....
void func(const std::optional<std::reference_wrapper<A>>& a)
{
if (a.has_value()) {
std::cout << a->get().get() << std::endl;
} else {
std::cout << "no value" << std::endl;
}
}
int main() {
A a(5);
func(std::ref(a));
}
(I suppose the missing const was a typo, because it would be an error in your example too even if A could be moved or copied).
Note that this does meet your requirements: Pass a std::optional and not use raw pointers. However, it is a little weird to use a reference (instead of pointer) because it cannot be null and then wrap that into an optional to allow "null" values. Using a raw pointer seems to be the most simple and straight forward solution.
Note that raw pointers are not "c-style". What can be considered c-style and what should be avoided by all means is raw owning pointers. When you want to pass a parameter to a function, and the function does not interfere with ownership, and it can either have a value or not a value then a raw pointer is just fine. Just do
void func(A* a)
{
if (a) {
std::cout << a->get() << std::endl;
} else {
std::cout << "no value" << std::endl;
}
}
int main() {
A a(5);
func(&a);
}

Template customization point with default behavior to do nothing

I have a generic code at which point I leave a possibility to modify data.
if (impl_.mode() == implementation_type::manual)
{
const auto steering = custom::customize_steering(impl_, input.steering());
impl_.output_interface()(steering);
return impl_.do_continue(impl_.params().period());
}
By default I want customize_steering to be optimized out.
Now I have it this way:
template<typename ImplT, typename SteeringT>
constexpr std::decay_t<SteeringT> customize_steering(ImplT &, SteeringT &&steering)
{
return std::forward<SteeringT>(steering);
}
Is it the right way to do or is it too convoluted and passing by const reference will do fine?
I decided to check, and I don't get the results I expect.
#include <iostream>
class foo
{
public:
foo() { std::cout << "Constructed" << std::endl; }
foo(const foo &) { std::cout << "Copy constructed" << std::endl; }
foo(foo &&) { std::cout << "Move constructed" << std::endl; }
~foo() { std::cout << "Destroyed" << std::endl; }
};
template<typename T>
std::decay_t<T> do_nothing(T &&t)
{
return std::forward<T>(t);
// return t;
}
int main(int, char **)
{
const auto &fcr = do_nothing(do_nothing(do_nothing(foo())));
const auto fc = do_nothing(fcr);
return 0;
}
The output is (MinGW64):
Constructed
Move constructed
Move constructed
Move constructed
Destroyed
Destroyed
Destroyed
Copy constructed
Destroyed
Destroyed
What I expected:
Without mandatory copy elision: Constructor -> Move constructor.
With mandatory copy elision (C++17): Constructor (for const auto fc).
How can I make it work?

template pass by const reference

I've looked over a few similar questions, but I'm still confused. I'm trying to figure out how to explicitly (not by compiler optimization etc) and C++03-compatible avoid copying of an object when passing it to a specialized template function. Here is my test code:
#include <iostream>
using namespace std;
struct C
{
C() { cout << "C()" << endl; }
C(const C&) { cout << "C(C)" << endl; }
~C() { cout << "~C()" << endl; }
};
template<class T> void f(T) { cout << "f<T>" << endl; }
// This shows two possible ways, I don't need two overloads
// If I do it like (2) the function is not called, only if I do it like (1)
template<> void f(C c) { cout << "f<C>" << endl; } // (1)
template<> void f(const C& c) { cout << "f<C&>" << endl; } // (2)
int main()
{
C c;
f(c);
return 0;
}
(1) accepts the object of type C, and makes a copy. Here is the output:
C()
C(C)
f<C>
~C()
~C()
So I've tried to specialize with a const C& parameter (2) to avoid this, but this simply doesn't work (apparently the reason is explained in this question).
Well, I could "pass by pointer", but that's kind of ugly. So is there some trick that would allow to do that somehow nicely?
EDIT: Oh, probably I wasn't clear. I already have a templated function
template<class T> void f(T) {...}
But now I want to specialize this function to accept a const& to another object:
template<> void f(const SpecificObject&) {...}
But it only gets called if I define it as
template<> void f(SpecificObject) {...}
Basically what I want to do with this specialization is to adapt the SpecificObject to the template interface like
template<> void f(SpecificObject obj){ f(obj.Adapted()); } // call the templated version
EDIT2: Ok, I can force the const C& specialization to be called this way:
f<const C&>(c);
but is there a way to make it work like this as just f(c)?
EDIT3: If someone would eventually have similar questions, I finally found this link in another question, and it is helpful: http://www.gotw.ca/publications/mill17.htm
You're conflating three issues: templates, overloading and argument passing.
Just remove the specializations and pass the argument as T const&.
Cheers & hth.,
Why don't you overload:
void f(const C& c) { cout << "f(const C&)" << endl; }
This would work:
int main()
{
C c;
f<const C&>(c);
return 0;
}
Your alternative:
template<typename T> void f(const boost::reference_wrapper<T const>& c)
{ cout << "f<boost_const_ref&>" << endl; }
int main()
{
C c;
f(boost::cref(c));
return 0;
}
In reality you would use boost::reference_wrapper to pass the reference through to where you want to use it. You can use get() to do that, although boost::reference_wrapper has an implicit conversion back to the reference, so you could probably get by without the partial-specialisation of the template and just passing boost::cref(c) to the regular one.
So if you don't always want to accept a const reference (which is reasonable for base types [int, long, float etc.]), you can use a little boost magic.
#include <iostream>
#include <boost/call_traits.hpp>
using namespace std;
struct C
{
C() { cout << "C()" << endl; }
C(const C&) { cout << "C(C)" << endl; }
//C& operator=(C const&) { cout << "C=C" << endl; return *this; }
~C() { cout << "~C()" << endl; }
};
template<class T> void foo(typename boost::call_traits<T>::param_type inst) { cout << "f<T>" << endl; }
// specialization for calling class C
template<> void foo<C>(boost::call_traits<C>::param_type inst) { cout << "f<C>" << endl; }
int main()
{
int i = 0;
foo<int>(i);
C c;
foo<C>(c);
return 0;
}
Your problem is that the actual parameter c isn't const, so the main template is a better match because it doesn't need to add 'const' to the type. If you try functions that pass by value and by non-const reference, the compiler will tell you that it cannot resolve that difference.
#include <iostream>
using namespace std;
struct C
{
C() { cout << "C()" << endl; }
C(const C&) { cout << "C(C)" << endl; }
~C() { cout << "~C()" << endl; }
};
template<class T> void f(const T&) { cout << "f<T>" << endl; }
int main()
{
C c;
f(c);
return 0;
}
This does do what you would like, but you must then use a const ref for all values passed into the function. I do not know if this was what you were looking for.

Template function's priority is different between vs2005 and vs2010

class Foo
{
friend class SquirrelVM;
public:
Foo() { cout << "Ctor" << endl; }
virtual ~Foo() { cout << "Dtor" << endl; }
Foo(const Foo & o) { cout << "const Ctor" << endl; }
template <typename _ty>
Foo(const _ty & val) { cout << "T const Ref" << endl; }
template <typename _ty>
Foo(_ty & val) { cout << "T Ref" << endl; }
template <typename _ty>
Foo(_ty * val) { cout << "T Ptr" << endl; }
};
Foo CreateFoo()
{
Foo ret;
return ret;
}
int main( int argc, char* argv[] )
{
Foo f = CreateFoo();
return 0;
}
Outputs are different between vs2005 and vs 2010.
Expected outputs are like this..
Ctor
const Ctor
Dtor
Dtor
Above outputs are derived if I build in vs2005.
But, vs2010's output is not same with vs2005's
Ctor
T Ref
Dtor
Dtor
Why template function's priority is higher than normal function in vs2010?
[edit]
If const is ommitted on copy constructor, than expected output(which is same with vs2005) comes out. Is there any side effect if form of copy constructor is not same with recomended form? Recomended form.. I mean... Foo(const Foo&); not Foo(Foo&);
Foo(_ty & val) with _ty being Foo is a better match because it will have parameter type Foo& matching a non-const Foo lvalue, while the other has a const that will make it a bit worse match.
There was some confusion during the made-up process of C++0x and before as to whether templates can be used to copy an object of a class to its own class type. The committee just recently figured they want to stop the confusion about it and allow such a thing. VS2010 seems to reflect that decision.