I was testing a move constructor and did the following:
#include <iostream>
#include <string>
using namespace std;
class X{
public:
int* p;
int size;
X(){}
X(int n) : size(n){
p = new int[n];
for(int i = 0; i < n; i++)
p[i] = i;
cout << "Constructor\n";
}
~X(){
delete[] p;
}
X(const X& r){
cout << "Copy\n";
}
X(X&& r){
p = r.p;
size = r.size;
r.p = NULL;
r.size = 0;
cout << "Move\n";
}
};
int main() {
X a(10); //constructor
X b(a); // copy
X c(X(3)); //constructor, move
return 0;
}
What I expected in the output is in the comments, but when compiling (VS 2012) move constructor is not called?! But, if I add additional parameter to constructor:
string name;
X(int n, string _name) : size(n), name(_name){
p = new int[n];
for(int i = 0; i < n; i++)
p[i] = i;
cout << "Constructor\n";
}
and then
X a(10, "a"); //constructor
X b(a); // copy
X c(X(3, "pom")); //constructor, move
i get results as expected... I really don't understand why.
EDIT: Now tested on GCC 4.7.2 and it does not call Move constructor in both cases but C++ Builder XE5 compiler calls Move constructor in both cases. Yet, VS calls it only in the second case (when using additional constructor parameter). Very interesting...
The compiler is eliding the move construction and directly constructing X(3) into c, essentially turning your initialization into
X c(3);
With gcc, you can disable this using the -fno-elide-constructors switch. Once you add that, the output from your original example is as expected:
Constructor
Copy
Constructor
Move
Live demo
Related
#include <iostream>
#include <string>
using namespace std;
class Class1 {
string s;
public:
Class1(const string& s_) : s(s_) {}
};
class Class2 {
string s;
public:
Class2(string s_) : s(std::move(s_)) {}
};
class Class3 {
string s;
public:
Class3(string s_) : s(s_) {}
};
int main()
{
string str = "ABC";
Class1 a(str);
Class2 b(str);
Class3 c(str);
}
I'm trying to find the cost of my constructor.
Class 1: cost 1 copy constructor
Class 2: cost 1 copy constructor and 1 move constructor
Class 3: cost 1 copy constructor + {A. nothing, B. move constructor, C. copy constructor}
Is the compiler smart enough to copy str directly into c.s ? What is the answer for the 3rd case?
Big edit: using a vector-like class, the answer is C. But is there any reason why the compiler can't steal s_ even when the object will be destructed after s(s_) ?
#include <iostream>
#include <string>
using namespace std;
template <typename T = int>
class MyVector {
private:
int n;
T* data;
public:
MyVector() {
n = 0;
data = nullptr;
cout << "MyVector default constructor\n";
}
MyVector(int _n) {
n = _n;
data = new T[n];
cout << "MyVector param constructor\n";
}
MyVector(const MyVector& other) {
n = other.n;
data = new T[n];
for (int i=0; i<n; i++) data[i] = other.data[i];
cout << "MyVector copy constructor\n";
}
MyVector(MyVector&& other) {
n = other.n;
data = other.data;
other.n = 0;
other.data = nullptr;
cout << "MyVector move constructor\n";
}
MyVector& operator = (const MyVector& other) {
if (this != &other) {
n = other.n;
delete[] data;
data = new T[n];
for (int i=0; i<n; i++) data[i] = other.data[i];
}
cout << "MyVector copy assigment\n";
return *this;
}
MyVector& operator = (MyVector&& other) {
if (this != &other) {
n = other.n;
delete[] data;
data = other.data;
other.n = 0;
other.data = nullptr;
}
cout << "MyVector move assigment\n";
return *this;
}
~MyVector() {
delete[] data;
cout << "MyVector destructor: size = " << n << "\n";
}
int size() {
return n;
}
};
class Class1 {
MyVector<> s;
public:
Class1(const MyVector<>& s_) : s(s_) {}
};
class Class2 {
MyVector<> s;
public:
Class2(MyVector<> s_) : s(std::move(s_)) {}
};
class Class3 {
MyVector<> s;
public:
Class3(MyVector<> s_) : s(s_) {}
};
int main()
{
MyVector<> vec(5);
cout << "-----------\n";
cout << "Class1\n";
Class1 a(vec);
cout << "\n------------\n";
cout << "Class3\n";
Class2 b(vec);
cout << "\n------------\n";
cout << "Class3\n";
Class3 c(vec);
cout << "\n------------\n";
return 0;
}
s_ is a lvalue in the initializer s(s_). So the copy constructor will be used to construct s. There is not automatic move like e.g. in return statements. The compiler is not allowed to elide this constructor call.
Of course a compiler can always optimize a program in whatever way it wants as long as observable behavior is unchanged. Since you cannot observe copies of a string being made if you don't take addresses of the string objects, the compiler is free to optimize the copies away in any case.
If you take a constructor argument to be stored in a member by-value, there is no reason not to use std::move.
This question already has an answer here:
C++ Deep copy of dynamic array through assignment operator
(1 answer)
Closed last year.
I try to learn copy constructors principle.
I have this code and I need to COPY data to testB data type.
Right now, I only copy pointers to previous memory but I need to copy all data.
Can you help me?
#include <cstdio>
#include <stdio.h>
struct Test {
int i, *p;
Test(int i): i(i), p(new int[i]){
p[0] = 1;
p[1] = 2;
p[2] = 3;
}
~Test() {
}
};
struct TestB : Test {
TestB(const Test &test) : Test(test){
p = new int[3];
p[0] = test.p[0];
p[1] = test.p[1];
p[2] = test.p[2];
i = test.i;
}
};
int main(){
Test test(3);
TestB b = test;
return 0;
}
First off, what you are trying to implement is a converting constructor, not a copy constructor, since you are trying to convert a Test object into a TestB object, rather than create a copy of a TestB object from another TestB object.
Since the array exists in Test, you should implement an actual copy constructor (and a copy assignment operator) in Test, and then TestB's converting constructor can call Test's copy constructor. Test's copy constructor can then allocate a new array that has the same number of items as the array being copied, and copy the values from the original array into the new array, eg:
#include <utility>
struct Test {
int i, *p;
Test(int i): i(i), p(new int[i]) {
for(int j = 0; j < i; ++j)
p[j] = j+1;
}
Test(const Test &src): i(src.i), p(new int[src.i]) {
for(int j = 0; j < i; ++j)
p[j] = src.p[j];
}
~Test() {
delete[] p;
}
// don't forget an assignment operator too, per the Rule of 3:
// https://en.cppreference.com/w/cpp/language/rule_of_three
Test& operator=(const Test &rhs) {
if (this != &rhs) {
Test tmp(rhs);
std::swap(i, tmp.i);
std::swap(p, tmp.p);
}
return *this;
}
};
struct TestB : Test {
TestB(const Test &test) : Test(test) {}
};
int main(){
Test test(3);
TestB b = test;
return 0;
}
That being said, you should use std::vector instead of new[], then you get all of the array management for free since std::vector already implements everything for you, eg:
#include <vector>
struct Test {
std::vector<int> p;
Test(int i): p(i) {
for(int j = 0; j < i; ++j)
p[j] = j+1;
}
};
struct TestB : Test {
TestB(const Test &test) : Test(test) {}
};
int main(){
Test test(3);
TestB b = test;
return 0;
}
#include < iostream >
using namespace std;
class A
{
public:
int x;
A(int i)
{
x= i;
cout<<"Constructor is Called "<<x<<endl;
}
~A()
{
cout<<"destructor is Called "<<x<<endl;
}
A(const A &a)
{
cout<<"in copy constructor a.x = "<<a.x<<endl;
cout<<" x = "<<x<<endl;
}
};
const A &fun(int i)
{
cout<<"in Fun"<<endl;
A t(i+1);
return(t);
}
main()
{
A *gg = new A(5);
A t = fun(2);
}
output of this is :
Constructor is Called 5
in Fun
Constructor is Called 3
destructor is Called 3
in copy constructor a.x = 0
x = 4067272
Why it is a.x=0 and x= 4067272?
Add code to initialize x in the copy constructor.
A(const A &a) : x(a.x)
//^^^^^^^^^^^^^^^ Missing code
{
cout<<"in copy constructor a.x = "<<a.x<<endl;
cout<<" x = "<<x<<endl;
}
Also,
fun returns a reference to a local variable. The reference is invalid after you return from fun. When you use A t = fun(2);, you are entering UB territory. You can't assume anything reasonable from it.
You can fix this by returning an object from fun instead of a const&.
A fun(int i)
{
cout<<"in Fun"<<endl;
A t(i+1);
return(t);
}
I have a question regarding how the destructor is called. For example, I created the following foo class and supplied with copy constructor, destructor and overloaded the assignment operator. I created a dynamic array of this foo objects and used the operator "=" to assign individual element of the array. I am very confused, immediately after the assignment operation, the destructor is called and when I want to access the data in the newly assigned object, I got very confusing result.Any suggestions?
#include <iostream>
using namespace std;
bool debug = true;
class foo{
private:
int n;
void init(int _n);
public:
int* arr; // just to make it accessible so that we can tract the contents;
foo(int _n);
foo(int* _a, int len);
foo(const foo & rhs);
foo & operator=(const foo & rhs);
~foo();
};
void foo::init(int _n = 0){
n = _n;
arr = new int[n];
for(int i = 0; i != n; i++) arr[i] = 0;
}
foo::foo(int _n = 0){
init(_n);
}
foo::foo(int*_a, int len){
init(len);
for(int i = 0; i< len; i++) arr[i] = _a[i];
}
foo::foo(const foo &rhs){
operator = (rhs);
}
foo& foo::operator= (const foo &rhs){
if(debug) cout<<"\nassignment operator overloaded";
if (this != &rhs){
if(n != 0) {
n = rhs.n;
delete [] arr;
arr = new int[n];
for(int i = 0; i < n; i++) arr[i] = rhs.arr[i];
}
}
return *this;
}
foo::~foo(){
if (debug)cout << "\ndestructor called\n";
delete []arr;
}
int main(){
{ // a explicit block to see when the destructor is called;
foo* f = new foo[4];
int n = 4;
int a[] = {0,1,2,3};
for(int i = 0; i < n;i++) {
cout<<i;
f[i] = foo(a, i);
cout<<f[i].arr[i]<<"\n"; // result is some seemingly random number;
}
}
system("PAUSE");
}*
When you do this:
f[i] = foo(a, i);
a temporary foo object is created on the RHS of the assignment operator. It is then used to assign to the foo on the LHS of the operator. Then, it is destroyed, therefore its destructor is called.
The reason for the garbage values after the assignments is probably that n is 0 in all the foos in the array. Your assignment operator is broken. You may want to have a look at the copy and swap idiom.
A big no no! Delegating initialization of an uninitialized object to the assignment operator is a no good idea:
foo::foo(const foo &rhs){
operator = (rhs);
}
Better is:
foo::foo(const foo &rhs)
: n(rhs.n), arr(new int[n])
{
// copy rhs.arr to arr
}
// Note: Passing by value:
foo& operator = (foo rhs) {
std::swap(n, rhs.n);
std::swap(arr, rhs.arr);
return *this;
// Note: The swapped rhs will do the cleanup in the destructor
}
You will end up with less coding and exception safety
Another issue is:
cout << f[i].arr[i] << "\n"
You are printing an undefined 'end' value (arr[i] == arr[n])
I'm trying to implement a container that allocated memory to the heap, but it seems as though my base constructor and my argument constructor don't like each other. Below, I've posted the code without anything commented out. As it stands, it crashes.
#include <iostream>
using namespace std;
class foo
{
public:
foo() {size=1; vals = new double[1]; vals[0]=0;}
~foo() {delete[] vals;}
foo(const foo& other)
{
size=other.getsize();
delete[] vals;
vals = new double[size];
for(long unsigned i=0; i<size; i++)
vals[i]=other[i];
}
foo& operator=(const foo& other)
{
size=other.getsize();
delete[] vals;
vals = new double[size];
for(long unsigned i=0; i<size; i++)
vals[i]=other[i];
return *this;
}
foo(double* invals, long unsigned insize)
{
size=insize;
delete[] vals;
vals = new double[size];
for(long unsigned i=0; i<size; i++)
vals[i]=invals[i];
}
double operator[](long unsigned i) const {return vals[i];}
long unsigned getsize() const {return size;}
private:
double* vals;
long unsigned size;
};
int main()
{
double bar[3] = {5,2,8};
foo B(bar, 3);
cout<< B[0]<< " "<< B[1]<< " "<< B[2]<<endl; //couts fine
foo A; //crashes here
return 0;
}
However, when I change main to be:
int main()
{
double bar[3] = {5,2,8};
foo B(bar, 3);
cout<< B[0]<< " "<< B[1]<< " "<< B[2]<<endl; //couts fine
foo A(); //works now
return 0;
}
It runs fine. But then I can't assign A = B because it thinks foo is a function or something.
I assume you have some really compelling reason not to use std::vector<double> here...
But anyway... in your copy constructor, you don't want to delete[] vals.
foo(const foo& other)
{
size=other.getsize();
vals = new double[size];
for(long unsigned i=0; i<size; i++)
vals[i]=other[i];
}
When the copy constructor is called, your object hasn't been initialized yet, so vals* doesn't even point to anything valid. Therefore, deleting it invokes undefined behavior (and your program crashes.) You only need to delete[] vals in your assignment operator.
Also, when you declare the Foo variable A, you don't want those parentheses after the variable name. Just say:
foo A;
When you place those parenthesis after the variable name, you're actually writing a function declaration using syntax inherited from C, and A becomes a function pointer type.