This question already has answers here:
What are copy elision and return value optimization?
(5 answers)
Closed 7 years ago.
#include <iostream>
using namespace std;
template <typename T> class tt
{
public :
int data;
tt()
{
std::cout << std::endl << " CONSTRUCTOR" << std::endl;
}
tt(const tt & that)
{
std::cout << std::endl << " COPY CONSTRUCTOR" << std::endl;
}
};
tt<int> test(void)
{
std::cout << std::endl << " INSIDE " << std::endl; tt<int> a; a.data =10 ;return a;
}
int main() {
// your code goes her
//tt<int> b;
tt<int> a =test();
cout<<a.data; //so that return value optimisation doesn't take place
return 0;
}
Why is the copy constructor not getting called in this case?
It gets called in the following case though
tt<int> b;
tt<int> a =b;
code link : http://ideone.com/e9lq3C
edit : This is not duplicate of What are copy elision and return value optimization?, because returned value is being referenced inside code.
a does not have a different location to the temporary. That is what copy elision and return value optimization do... they make it so that you don't get a temporary. Where you say a in test(), the optimization means you are referring to the same location as a in main. So no copy is required.
This is all due to compiler optimization (at least RVO). Compilers ends up creating one and only one object her (the one you asked to be created locally in test() becomes the same object as your a variable).
Related
This question already has an answer here:
Placement new and assignment of class with const member
(1 answer)
Closed 4 years ago.
The 2 print statements print different numbers. As far as I can see I'm not doing any dodgy const_cast here so I'm not sure what UB I could have possibly committed.
Is this code well-formed?
Can the compiler rely on the fact that A::num is const so it's allowed to print the same number ?
Code:
struct A
{
const int num = 100;
A() {}
A(int in) : num{in} {}
void call()
{
new (this) A{69};
}
};
int main()
{
A a;
std::cout << a.num << '\n';
a.call();
std::cout << a.num << '\n';
}
No, your code has UB. Remove the const on num and you don't get any UB anymore.
The problem is that the standard provides a guarantee that a const object doesn't change. But if you reuse the same storage, then you can "modify" the const object in a way.
[basic.life]p8 explicitly prohibits this by saying that the old name of the object only refers to the new object under certain conditions. One of them is that your class doesn't have any const members. So by extension, your second a.num is UB, as the a refers to the old destructed object.
However, there are two ways to avoid this UB. First, you can store the pointer to the new object:
struct A *new_ptr;
struct A {
// [...]
void call() {
new_ptr = new (this) A{69};
}
};
int main()
{
A a;
std::cout << a.num << '\n';
a.call();
std::cout << new_ptr->num << '\n'; // ok
}
Or use std::launder:
std::cout << std::launder(&a)->num << '\n'; // second access
This question already has answers here:
What are copy elision and return value optimization?
(5 answers)
Closed 7 years ago.
I wrote this:
#include <iostream>
struct A
{
int a;
int b;
A() : a(10) { std::cout << "default ctor" << std::endl;}
~A(){ }
A(const A&){ std::cout << "copy ctor" << std::endl; }
A(const A&&){ std::cout << "move ctor" << std::endl; }
};
A init()
{
A a;
a.b = 20;
return a;
}
int main()
{
A a = init();
std::cout << a.b << std::endl;
}
I expected that A a = init() imposes the move-contructor call, but the outpur is:
default ctor
20
DEMO
The line
A a = init();
is inlined by NRVO. It creates an object by using it's default constructor in its segment of code:
A a;
Your move constructor will not be used here.
The move constructor here can be used with -fno-elide-constructors compiler flag. I've modified your example to compile it with this flag. But note, that default constructor will always be called because NRVO does not affect this in your code. NRVO only means that the object will be constructed in the storage that it is needed (not on the stack of your init method) so it would not be moved or copied. With the no-elide flag it can't be created there so it would be copied/moved there.
This question already has answers here:
Why is value taking setter member functions not recommended in Herb Sutter's CppCon 2014 talk (Back to Basics: Modern C++ Style)?
(4 answers)
Closed 7 years ago.
Assume I have the following class, which has a method set_value. Which implementation is better?
class S {
public:
// a set_value method
private:
Some_type value;
};
Pass by value, then move
void S::set_value(Some_type value)
{
this->value = std::move(value);
}
Define two overloaded methods
void S::set_value(const Some_type& value)
{
this->value = value;
}
void S::set_value(Some_type&& value)
{
this->value = std::move(value);
}
The first approach requires definition of one method only while the second requires two.
However, the first approach seems to be less efficient:
Copy/Move constructor for the parameter depending on the argument passed
Move assignment
Destructor for the parameter
While for the second approach, only one assignment operation is performed.
Copy/Move assignment depending on which overloaded method is called
So, which implementation is better? Or does it matter at all?
And one more question: Is the following code equivalent to the two overloaded methods in the second approach?
template <class T>
void S::set_value(T&& value)
{
this->value = std::forward<T>(value);
}
The compiler is free to elide (optimise away) the copy even if there would be side effects in doing so. As a result, passing by value and moving the result actually gives you all of the performance benefits of the two-method solution while giving you only one code path to maintain. You should absolutely prefer to pass by value.
here's an example to prove it:
#include <iostream>
struct XYZ {
XYZ() { std::cout << "constructed" << std::endl; }
XYZ(const XYZ&) {
std::cout << "copy constructed" << std::endl;
}
XYZ(XYZ&&) noexcept {
try {
std::cout << "move constructed" << std::endl;
}
catch(...) {
}
}
XYZ& operator=(const XYZ&) {
std::cout << "assigned" << std::endl;
return *this;
}
XYZ& operator=(XYZ&&) {
std::cout << "move-assigned" << std::endl;
return *this;
}
};
struct holder {
holder(XYZ xyz) : _xyz(std::move(xyz)) {}
void set_value(XYZ xyz) { _xyz = std::move(xyz); }
void set_value_by_const_ref(const XYZ& xyz) { _xyz = xyz; }
XYZ _xyz;
};
using namespace std;
auto main() -> int
{
cout << "** create named source for later use **" << endl;
XYZ xyz2{};
cout << "\n**initial construction**" << std::endl;
holder h { XYZ() };
cout << "\n**set_value()**" << endl;
h.set_value(XYZ());
cout << "\n**set_value_by_const_ref() with nameless temporary**" << endl;
h.set_value_by_const_ref(XYZ());
cout << "\n**set_value() with named source**" << endl;
h.set_value(xyz2);
cout << "\n**set_value_by_const_ref() with named source**" << endl;
h.set_value_by_const_ref(xyz2);
return 0;
}
expected output:
** create named source for later use **
constructed
**initial construction**
constructed
move constructed
**set_value()**
constructed
move-assigned
**set_value_by_const_ref() with nameless temporary**
constructed
assigned
**set_value() with named source**
copy constructed
move-assigned
**set_value_by_const_ref() with named source**
assigned
note the absence of any redundant copies in the copy/move versions but the redundant copy-assignment when calling set_value_by_const_ref() with nameless temporary. I note the apparent efficiency gain of the final case. I would argue that (a) it's a corner case in reality and (b) the optimiser can take care of it.
my command line:
c++ -o move -std=c++1y -stdlib=libc++ -O3 move.cpp
This question already has answers here:
Why is the destructor of the class called twice?
(5 answers)
Closed 9 years ago.
#include <iostream>
using namespace std;
class A
{
public:
A() { cout << "A's constructor" << endl; }
~A() { cout << "A's destructor" << endl; }
};
class B
{
public:
operator A() const { return A(); }
};
void f(A q) {}
int main()
{
B d1;
f(d1);
return 0;
}
Here's what I expected the code to do before I ran it:
The call to f results in a call to the converter function in class B which returns a temporary object. q's constructor gets called and when f exits, q's destructor gets called. I expected the following output:
A's constructor
A's destructor
but the output I got was:
A's constructor
A's destructor
A's destructor
Since there's another destructor, an extra object must have been created somewhere. Can someone explain what's happening here?
Use this as your class A:
class A
{
public:
A() { cout << "A's constructor: " << this << endl; }
A(const A& a) { cout << "A's copy constructor: " <<this << " form " << &a << endl; }
A(A&& a) { cout << "A's move constructor: " <<this << " form " << &a << endl; }
A& operator=(const A& a) { cout << "A's assignment" <<this << " form " << &a << endl; }
~A() { cout << "A's destructor: "<< this << endl; }
};
And you'll see why.
The question has been asked many times before, but since it is so generic it is difficult to find the older posts.
You are passing your objects around by value, meaning that the copies are created by copy constructor. Copy constructor is what created that "extra object" in your case. Meanwhile, you do not output anything from the copy constructor and therefore don't see the calls.
You have to add a debug output to your copy-constructor as well. That way you will see what is actually constructed and when.
There's potential for there to be 3 A objects constructed here. First is the temporary object created by A() in the conversion operator. Then, since the return type of the conversion operator is A, that temporary is copied into the return value. Then the return value of the conversion is copied into the parameter q of f.
To copy an object, the copy constructor is invoked. The default constructor will not be invoked, so you won't see the "A's constructor" message being printed.
It just so happens that the compiler elides one of these copies so that you only actually have one copy occur. Which one is being elided, I can't tell you (but it's probably the copy into the return value).
I think first destructor call for temporary object and second destructor for object which is constructed by move semantic.
In the following code the line that creates nested object prints only "constructor" with gcc, but not with VS 2013:
#include <iostream>
using namespace std;
struct test {
test() { cout << "constructor" << endl; }
test(const test&) { cout << "copy constructor" << endl; }
test(test&&) { cout << "move constructor" << endl; }
~test() { cout << "destructor" << endl; }
};
struct nested {
test t;
// nested() {}
};
auto main() -> int {
// prints "constructor", "copy constructor" and "destructor"
auto n = nested{};
cout << endl;
return 0;
}
Output:
constructor
copy constructor
destructor
destructor
So I guess what happening here is that a temporary object gets copied into n. There is no compiler-generated move constructor, so that's why it's not a move.
I'd like to know if this is a bug or an acceptable behaviour? And why adding a default constructor prevents a copy here?
It's not auto that's the problem; the following will exhibit the same:
nested n = nested{};
The temporary is being direct-initialized with {}, and then n is being copy-initialized with that, because test is a class-type (in this case, has user-defined constructor).
An implementation is permitted to directly initialize the ultimate target (n), but isn't obligated to, so either is legal.
Lots (really, lots) of details in 8.5 and 8.5.1 of the Standard.
This is a failure of MSVC to do copy elision (I'd guess related to the brace-init-constructor). It's perfectly legal both ways.