Assignment at Initialization without Default Constructor - c++

In this program, I completely understand why the first part of the main function fails and needs to be commented - there's no implicit default ctor after I've implemented the value ctor within TestingClass. Perfectly logical. However, I was a bit surprised to find that the second part (creation of test2 object) succeeds just fine, at least with gcc 4.8.4.
#include <iostream>
using namespace std;
class TestingClass
{
public:
TestingClass(int inVal)
{
val = inVal;
}
int val;
};
TestingClass testingCreator()
{
return TestingClass(100);
}
int main()
{
/*
TestingClass test1;
test1 = testingCreator();
cout << "Test1: " << test1.val << endl;
*/
TestingClass test2 = testingCreator();
cout << "Test2: " << test2.val << endl;
}
Thinking about it, it also makes sense, because the object, test2, will never have existed without having been constructed / initialized, but most people think of initialization in this way as just being a declaration and an assignment on one line. Clearly, though, initialization is more special than that, since this code works.
Is this standard C++? Is it guaranteed to work across compilers? I'm interested in how initialization in this way is different than just declare (using a default ctor) and then assign (via a temporary object created in the global function).
UPDATE: Added a copy ctor and a third case that clearly uses the copy ctor.
#include <iostream>
using namespace std;
class TestingClass
{
public:
TestingClass(const TestingClass &rhs)
{
cout << "In copy ctor" << endl;
this->val = rhs.val + 100;
}
TestingClass(int inVal)
{
val = inVal;
}
int val;
};
TestingClass testingCreator()
{
return TestingClass(100);
}
int main()
{
/*
TestingClass test1;
test1 = testingCreator();
cout << "Test1: " << test1.val << endl;
*/
TestingClass test2 = testingCreator();
cout << "Test2: " << test2.val << endl;
TestingClass test3(test2);
cout << "Test3: " << test3.val << endl;
}
This outputs:
Test2: 100
In copy ctor
Test3: 200

Your thinking on what TestingClass test2 = testingCreator(); does is flawed. When you see
type name = stuff;
You do not create name and then assign to it stuff. What you do is copy initialize name from stuff. This means you call the copy or move constructor. Generally this call can be elided by optimizing compilers but if it was not then that is what you would see. In either case the default constructor is never called.
In your first example
TestingClass test1;
Forces the default constructor to be called and since you do not have one you get an error.

test2 is defined by the copy constructor of TestingClass, taking the result of testingCreator as argument. The copy constructor TestingClass::TestingClass(const TestingClass&) is automatically generated by the compiler and the C++ standard guarantees that it copies the val field.

Related

Strange object assignment behaviour c++

I have a strange behavior with object assignments. I will much appreciate, if you can explain why this assignment works like this. It has cost me already a lot of time.
I am using Visual Studio Enterprise 2017 (all default settings).
Code:
#include "stdafx.h"
#include <iostream>
using namespace std;
class Test
{
public:
Test()
{
cout << "Constructor of " << this << endl;
}
~Test()
{
cout << "Destructor of " << this << endl;
}
};
int main()
{
cout << "Assignment 1" << endl;
auto t = Test();
cout << "Assignment 2" << endl;
t = Test();
int i = 0;
cin >> i;
return 0;
}
Output (up to cin):
Assignment 1
Constructor of 006FFC9F
Assignment 2
Constructor of 006FFBC7
Destructor of 006FFBC7
Expected Output (up to cin):
Assignment 1
Constructor of 006FFC9F
Assignment 2
Destructor of 006FFC9F
Constructor of 006FFBC7
I wanted to write a test function which creates an object of my (template) class, do some tests, then create a new object and do some more testing. The problem is that t holds the already destructed object after the second assignment.
I know that I can just use dynamic allocation which results in the expected behavior, but why does this program behave different?
Thank you very much.
Regards.
PS: Results are the same, independent of Release/Debug or 64/32 bit compilation
EDIT: More verbose example:
#include "stdafx.h"
#include <iostream>
using namespace std;
class Test
{
private:
float* val;
public:
Test()
{
val = new float;
cout << "Constructor of " << this << ", addr. of val: " << val << endl;
}
~Test()
{
cout << "Destructor of " << this << ", addr. of val: " << val << " --> DELETING VAL!" << endl;
delete val;
}
float* getVal() { return this->val; }
};
int main()
{
cout << "Assignment 1" << endl;
auto t = Test();
cout << "Assignment 2" << endl;
t = Test();
cout << "Val Address: " << t.getVal() << endl;
int i = 0;
cin >> i;
return 0;
}
Output (it holds a deleted pointer at the end!!!):
Assignment 1
Constructor of 004FFBDC, addr. of val: 0072AEB0
Assignment 2
Constructor of 004FFB04, addr. of val: 00723928
Destructor of 004FFB04, addr. of val: 00723928 --> DELETING VAL!
Val Address: 00723928
With
auto t = Test();
you actually construct two objects. First is the Test() which constructs a temporary object. The second is the construction of t which is made through copy-construction. There is no assignment being made here, even if the = operator is used, it's copy-construction.
If you add a copy-constructor to the Test class similar to your constructor and destructor, you should see it clearly.
As for
t = Test();
here a temporary object is created with Test(). That temporary object is then passed to the (compiler-generated) assignment operator of the Test class, and then the temporary object is promptly destructed.
The object t itself is not destructed, it should not be as it is the destination of the assignment.
Your confusion seems to be a mistaken expectation that the original object is destroyed when assignment takes place. Like, in this code:
cout << "Assignment 2" << endl;
t = Test();
This piece of code invokes the move-assign operator. Since you didn't define one, the default one generated by the compiler is more-or-less going to look like this:
Test & operator=(Test &&) {}
Note how there's no invocation of a constructor or (critically) a destructor in that code. The only Constructors and Destructors that are going to run are on the temporary object (which is what you observe in the actual output). The original object doesn't get destroyed until the code goes out of scope; and why would it? It's not like you can stop using the stack space before then.
Edit: Something which might help you understand what's going on:
#include<iostream>
struct Test {
Test() {std::cout << "Constructed.\n";}
~Test() {std::cout << "Destructed.\n";}
Test(Test const&) {std::cout << "Copy-Constructed.\n";}
Test(Test &&) {std::cout << "Move-Constructed.\n";}
Test & operator=(Test const&) {std::cout << "Copy-Assigned.\n"; return *this;}
Test & operator=(Test &&) {std::cout << "Move-Assigned.\n"; return *this;}
};
int main() {
std::cout << "Test t;\n";
Test t; //Construction
std::cout << "Test t2(t);\n";
Test t2(t); //Copy-Construct
std::cout << "Test t3(std::move(t2));\n";
Test t3(std::move(t2)); //Move-Construct
std::cout << "Test t4 = t;\n";
Test t4 = t; //Copy Construct, due to Copy Ellision
std::cout << "Test t5 = Test();\n";
Test t5 = Test(); //Will probably be a normal Construct, due to Copy Ellision
std::cout << "t = t2;\n";
t = t2; //Copy Assign
std::cout << "t = Test();\n";
t = Test(); //Move Assign, will invoke Constructor and Destructor on temporary
std::cout << "Done! Cleanup will now happen!\n";
return 0;
}
Results as seen when compiled here:
Test t;
Constructed.
Test t2(t);
Copy-Constructed.
Test t3(std::move(t2));
Move-Constructed.
Test t4 = t;
Copy-Constructed.
Test t5 = Test();
Constructed.
t = t2;
Copy-Assigned.
t = Test();
Constructed.
Move-Assigned.
Destructed.
Done! Cleanup will now happen!
Destructed.
Destructed.
Destructed.
Destructed.
Destructed.
DOUBLE EDIT COMBO!:
As I mentioned in comments, val is just a pointer. 8 bytes (on a 64-bit machine) allocated as part of Test's storage. If you're trying to make sure that Test always contains a valid value for val that hasn't been deleted, you need to implement the Rule of Five (previously known as the Rule of Three):
class Test {
float * val;
public:
Test() {val = new float;}
~Test() {delete val;
Test(Test const& t) {
val = new float(*(t.val));
}
Test(Test && t) {std::swap(val, t.val);}
Test & operator=(Test const& t) {
float * temp = new float(*(t.val)); //Gives Strong Exception Guarantee
delete val;
val = temp;
return *this;
}
Test & operator=(Test && t) {std::swap(val, t.val); return *this;};
float & get_val() const {return *val;} //Return by reference, not by pointer, to
//prevent accidental deletion.
};

How does std::map call value destructors?

I have this code :
#include <iostream>
#include <map>
using namespace std;
class test{
public:
test() {
cout << "calling test ctor " << endl;
}
~test() {
cout << "calling test dtor " << endl;
}
void callme(){
cout << "call me " << endl;
}
};
int main () {
map<int, test> mp;
mp[0].callme();
mp[0].callme();
return 0;
}
The output of this program is :
calling test ctor
calling test dtor
calling test dtor
call me
call me
calling test dtor
I am little confused how std::map is handling test:: ctors and dtors here.
Before executing this code, my assumption was that mp[0].callme() would create a new test object and call callme() on that, and if we call mp[0].callme() again, then it should call test:: dtor (since we are replacing the key 0 here) and then test:: ctor to create a new test object so that it could call callme() on that. Obviously my assumption is wrong here because output doesn't match at all.
Could anyone please throw some light on this ?
EDIT1:
gcc --version = gcc (GCC) 5.1.1 20150422 (Red Hat 5.1.1-1)
Command to compile:
g++ maps.cpp
So, no flags with g++. Simple compile.
By compiling using the command g++ maps.cpp, you're invoking g++ in C++03 mode, which means it isn't able to use move semantics.
The relevant lines of the map::operator[] implementation can be found here
if (__i == end() || key_comp()(__k, (*__i).first))
#if __cplusplus >= 201103L
__i = _M_t._M_emplace_hint_unique(__i, std::piecewise_construct,
std::tuple<const key_type&>(__k),
std::tuple<>());
#else
__i = insert(__i, value_type(__k, mapped_type()));
#endif
So prior to C++11, the mapped_type (test in your example) is default constructed to create a value_type (pair<int const, test> in your example). This is the initial call to the constructor.
The call to insert then has to copy the mapped type at least once when it inserts it into the internal storage for the map. Evidently, the libstdc++ implementation results in an additional copy somewhere, adding up to two copy constructions, and hence two matching destructor calls. If you add a copy constructor definition you'll see the number of destructor calls match the number of constructor calls.
Live demo
Also, notice that by adding the -std=c++11 flag, you avoid the intermediate copies. As seen in the code above, the implementation uses piecewise construction of the pair in that case to directly construct the mapped_type (and key_type) in the map's internal storage.
Apparently, your operator[] uses the following logic:
If the object doesn't exist, create it and then set it equal to a default-constructed object.
Return a reference to the object.
That is very strange behavior. The extra construction and assignment is not needed. The new object should just be default constructed in the first place.
For completeness:
#include <iostream>
#include <map>
using namespace std;
class test{
public:
test() {
cout << "calling test ctor " << endl;
}
test(const test&) {
cout << "calling copy ctor " << endl;
}
// test(test&&) {
// cout << "calling move ctor " << endl;
// }
test& operator = (const test&) {
cout << "calling copy assignment " << endl;
return * this;
}
// test& operator = (test&&) {
// cout << "calling move assignment " << endl;
// return * this;
// }
~test() {
cout << "calling test dtor " << endl;
}
void callme(){
cout << "call me " << endl;
}
};
int main () {
map<int, test> mp;
mp[0].callme();
mp[0].callme();
return 0;
}
Compiled without C++11 gives:
calling test ctor
calling copy ctor
calling copy ctor
calling test dtor
calling test dtor
call me
call me
calling test dtor
Having comments on move semantics removed and compiled with C++11:
calling test ctor
call me
call me
calling test dtor
Both are compiled with g++ 4.8.4

why c++ auto object optimization is happening in this code?

Why only one object of A is created in this program? and no copy constructor is called. What is this optimization called? If this is a valid/known optimization, will it not be a trouble for multiton design pattern?
#include <iostream>
#include <stdio.h>
using namespace std;
class A
{
public:
A () {
cout << "in-- Constructor A" << endl;
++as;
}
A (const A &a) {
cout << "in-- Copy-Constructor A" << endl;
++as;
}
~A() {
cout << "out --Constructor A" << endl;
--as;
}
A & operator=(const A &a) {
cout << "assignment" << endl;
++as;
//return *this;
}
static int as;
};
int A::as = 0;
A fxn() {
A a;
cout << "a: " << &a << endl;
return a;
}
int main() {
A b = fxn();
cout << "b: " << &b << endl;
cout << "did destructor of object a in func fxn called?" << endl;
return 0;
}
Output of above program
in-- Constructor A
a: 0x7fffeca3bed7
b: 0x7fffeca3bed7
did destructor of object a in func fxn called?
out --Constructor A
Go through link http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/
It will help you.
This seems to be a case of a return value optimization. This optimization is notable in the C++ world as it is allowed to change the observable behavior of the program. It's one of the few, if not the only, optimization that's allowed to do that, and it's from the days where returning copies was considered a weakness. (With move semantics and generally faster machines, this is much, much less of an issue now.)
Basically, the compiler sees that it's going to copy the object, so instead it allocates room for it on the calling frame and then builds it there instead of calling the copy constructor.

initializing struct while using auto causes a copy in VS 2013

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.

c++ compiler free to choose between user defined and compiler generated copy-constructors?

I have the following sample code (a stripped down version of my programme)
Class 'some_class' has a constructor with default parameters. The compiler is able to recognise this constructor as a copy constructor. In the main function, this constructor is called when I order for a copy constructed object called 'b'. But when I construct 'c' from a function result, the compiler calls a compiler generated copy constructor (which copies the bit pattern). I can tell by the value of c.some_data, which should have been set by my own copy constructor to a value of 2.
1) What does the standard say about this?
2) Is my compiler broken?
I use MinGW with no options but a specification of my source file name and a name for the executable. I got my port of the gnu open source compiler from the official MinGW website, I'm using the latest version. Have I found a bug, or is this due to my (mis)understanding of c++?
Thanks in advance
#include <iostream>
#include <string>
class some_class
{
public:
some_class(int p = 0) :
some_data(p)
{
std::cout << "user defined constructor (p = " << p << ")" << std::endl;
}
some_class(const some_class &, int = 0)
{
std::cout << "user defined copy constructor" << std::endl;
some_data = 2;
}
int some_data;
};
extern some_class some_function_returning_some_class_object();
int main(int, char **)
{
std::cout << "creating a, with no parameters" << std::endl;
some_class a;
std::cout << "creating b, a copy of a" << std::endl;
some_class b = a;
std::cout << "creating c, copy constructed from a function result" << std::endl;
some_class c = some_function_returning_some_class_object();
std::cout << "c.some_data = " << c.some_data << std::endl;
}
some_class some_function_returning_some_class_object()
{
some_class a(1);
return a;
}
The output is as follows:
creating a, with no parameters
user defined constructor (p = 0)
creating b, a copy of a
user defined copy constructor
creating c, copy constructed from a function result
user defined constructor (p = 1)
c.some_data = 1
The compiler is not using the compiler-defined default copy constructor. It is presumably using return value optimization to skip the copy altogether.