In the code below, Class A has a vector of ints. Class B inherits from A and has an iterator to the vector. The constructor of B initializes the iterator of B. But when we print, we get garbage. Why does the cout in main print garbage? Am I missing something?
#include <iostream>
#include <vector>
class A {
public:
A() {}
A(const A& copyFrom) : intList(copyFrom.intList) {} //copy constructor
virtual ~A() {}
void populateList()
{
for(int i=10; i<100; i++)
{
intList.push_back(i);
}
}
protected:
std::vector<int> intList;
};
class B : public A {
public:
B() : A() {}
B(const A& a) : A(a), intIt(intList.begin())
{
std::cout << "constructor with base class param called" << std::endl;
}
B(const B& b) : A(b), intIt(intList.begin()) //copy constructor
{
std::cout << "copy constructor called" << std::endl;
}
std::vector<int>::iterator intIt;
};
int main() {
A a;
a.populateList();
B b ;
b = B(a);
std::cout << *b.intIt << std::endl; //prints garbage. why?
}
Thanks!
B b ;
b = B(a); //the copy constructor of B is not called here. Why?
The operation in that line is assignment, not copy constructor. The copy constructor would be:
B b = someotherB;
Note that semantically this is also copy-constructing:
B b = B(a);
But the compiler will more often than not elide the copy contruction by creating B(a) in place of b.
The expression b = B(a) separated from declaration is assignment, not copy construction. This is one of the confusing things about C++:
Foo x(y); // copy-construction
Foo x = y; // also copy-construction, equivalent to the above
Foo x; x = y; // default-construction followed by assignment, different
// (and possibly less efficient) than the above
Failing to define an assignment operator will create a default one that performs member-wise assignment. This is OK for the intList member, but the assigned intIt will keep pointing to the old list, which in your case belongs to the temporary reference to B created by the B(a) expression. As soon as this reference is destroyed (which is at the end of the outermost expression), its intList is destroyed and the iterator becomes invalid.
In other words, B b; b = B(a) is equivalent to:
B b; // constructor
{
B tmp(a); // copy constructor
b = tmp; // member-wise assignment
// at this point, b.intList is a copy of tmp.intList, but b.intIt
// points to the beginning of tmp.intList, not to the beginning of
// b.intList
}
// tmp is destroyed and b.intIt now points to the beginning of a deleted list
It is your responsibility to define an assignment operator that maintains the invariant of intIt referring to an element in intList; for example:
B& operator=(const B& rhs)
{
intList = rhs.intList;
intIt = intList.begin() + (rhs.intIt - rhs.intList.begin());
std::cout << "assignment called" << std::endl;
return *this;
}
Also note that all iterators into the vector are invalidated when you change the size of the vector, even if you only append with push_back(). So populateList(), and other methods that can change the size of the vector should be overridden in B to also recalculate intIt. For these reasons it would be a better idea to avoid using an iterator and simply store the position into the vector, and have a function that returns intList.begin() + pos, thus creating an iterator on-demand that is guaranteed to be valid. Then you wouldn't need to define neither a copy-constructor nor an assignment operator, as the compiler-supplied defaults would work just fine.
The Copy construction will not be called because you are not assigning object of same class
b = B(a); //the copy constructor of B is not called here. Why?
in above code below constructor will be called because you are passing object of type A
B(const A& a) : A(a), intIt(intList.begin())
{
std::cout << "constructor with base class param called" << std::endl;
}
Iterator value will not be usable because you are not initializing it
std::cout << *(b.intIt) << std::endl; //prints garbage. why?
you need to initalize it
std::vector<X>::iterator iter; //no particular value
iter = some_vector.begin(); //iter is now usable
Related
From what I learned, I thought Foo a = 1 is equivalent to Foo a = (Foo)1.
With copy constructor declared, yes, they both result in calling Converting constructor.
class Foo
{
public:
// Converting constructor
Foo(int n) : value_(n) { std::cout << "Converting constructor." << std::endl; }
// Copy constructor
Foo(const Foo&) { std::couut << "Copy constructor." << std::endl; }
private:
int value_;
};
int main()
{
Foo a = 1; // OK - prints only "Converting constructor."
Foo b = (Foo)1; // OK - prints only "Converting constructor."
}
In contrast, without copy constructor, it doesn't compile even though it doesn't ever call copy constructor.
class Foo
{
public:
// Converting constructor
Foo(int n) : value_(n) { std::cout << "Converting constructor." << std::endl; }
// Copy constructor deleted
Foo(const Foo&) = delete;
private:
int value_;
};
int main()
{
Foo a = 1; // OK - prints only "Converting constructor."
Foo b = (Foo)1; // Error C2280: 'Foo::Foo(const Foo &)': attempting to reference a deleted function
}
What makes difference?
Thank you.
Foo a = 1; calls Foo(int n). (Foo)1 also calls Foo(int n). Foo b = (Foo)1; calls copy constructor Foo(const Foo&). Until C++17 the last call can be elided but the copy constructor must be available. Since C++17 copy elision is mandatory and the copy constructor isn't necessary: https://en.cppreference.com/w/cpp/language/copy_elision
Probably you're using a C++ standard before C++17 and the copy constructor is required but not called.
"From what I learned, I thought Foo a = 1 is equivalent to Foo a = (Foo)1." That's not equivalent. The first is one constructor call and the second is two constructor calls but one call can/must be elided.
I wrote the following c++ code trying to understand copy elision in c++.
#include <iostream>
using namespace std;
class B
{
public:
B(int x ) //default constructor
{
cout << "Constructor called" << endl;
}
B(const B &b) //copy constructor
{
cout << "Copy constructor called" << endl;
}
};
int main()
{
B ob =5;
ob=6;
ob=7;
return 0;
}
This produces the following output:
Constructor called
Constructor called
Constructor called
I fail to understand why is the constructor being called thrice with each assignment to object ob.
B ob =5;
This uses the given constructor.
ob=6;
This uses the given constructor because there is not a B& operator=(int) function and 6 must be converted to type B. One path to do this is to temporarily construct a B and use it in the assignment.
ob=7;
Same answer as above.
I fail to understand why is the constructor being called thrice with each assignment
As I stated above you do not have a B& operator=(int) function but the compiler is happy to provide a copy assignment operator (i.e., B& operator=(const B&);) for you automatically. The compiler generated assignment operator is being called and it takes a B type and all int types can be converted to a B type (via the constructor you provided).
Note: You can disable the implicit conversion by using explicit (i.e., explicit B(int x);) and I would recommend the use of explicit except when implicit conversions are desired.
Example
#include <iostream>
class B
{
public:
B(int x) { std::cout << "B ctor\n"; }
B(const B& b) { std::cout << B copy ctor\n"; }
};
B createB()
{
B b = 5;
return b;
}
int main()
{
B b = createB();
return 0;
}
Example Output
Note: Compiled using Visual Studio 2013 (Release)
B ctor
This shows the copy constructor was elided (i.e., the B instance in the createB function is triggered but no other constructors).
Each time you assign an instance of the variable ob of type B an integer value, you are basically constructing a new instance of B thus calling the constructor. Think about it, how else would the compiler know how to create an instance of B if not through the constructor taking an int as parameter?
If you overloaded the assignment operator for your class B taking an int, it would be called:
B& operator=(int rhs)
{
cout << "Assignment operator" << endl;
}
This would result in the first line: B ob = 5; to use the constructor, while the two following would use the assignment operator, see for yourself:
Constructor called
Assignment operator
Assignment operator
http://ideone.com/fAjoA4
If you do not want your constructor taking an int to be called upon assignment, you can declare it explicit like this:
explicit B(int x)
{
cout << "Constructor called" << endl;
}
This would cause a compiler error with your code, since it would no longer be allowed to implicitly construct an instance of B from an integer, instead it would have to be done explicitly, like this:
B ob(5);
On a side note, your constructor taking an int as parameter, is not a default constructor, a default constructor is a constructor which can be called with no arguments.
You are not taking the assignment operator into account. Since you have not defined your own operator=() implementation, the compiler generates a default operator=(const B&) implementation instead.
Thus, your code is effectively doing the following logic:
#include <iostream>
using namespace std;
class B
{
public:
B(int x) //custom constructor
{
cout << "Constructor called" << endl;
}
B(const B &b) //copy constructor
{
cout << "Copy constructor called" << endl;
}
B& operator=(const B &b) //default assignment operator
{
return *this;
}
};
int main()
{
B ob(5);
ob.operator=(B(6));
ob.operator=(B(7));
return 0;
}
The compiler-generated operator=() operator expects a B object as input, but you are passing an int value instead. Since B has a non-explicit constructor that accepts an int as input, the compiler is free to perform an implicit conversion from int to B using a temporary object.
That is why you are seeing your constructor invoked three times - the two assignments are creating temporary B objects.
#include <string>
#include <iostream>
#include <utility>
struct A {
std::string s;
A() : s("test") {}
A(const A& o) : s(o.s) { std::cout << "move failed!\n"; }
A(A&& o) : s(std::move(o.s)) {}
A& operator=(const A&) { std::cout << "copy assigned\n"; return *this; }
A& operator=(A&& other) {
s = std::move(other.s);
std::cout << "move assigned\n";`enter code here`
return *this;
}
};
A f(A a) { return a; }
struct B : A {
std::string s2;
int n;
// implicit move assignment operator B& B::operator=(B&&)
// calls A's move assignment operator
// calls s2's move assignment operator
// and makes a bitwise copy of n
};
struct C : B {
~C() {}; // destructor prevents implicit move assignment
};
struct D : B {
D() {}
~D() {}; // destructor would prevent implicit move assignment
//D& operator=(D&&) = default; // force a move assignment anyway
};
int main()
{
A a1, a2;
std::cout << "Trying to move-assign A from rvalue temporary\n";
a1 = f(A()); // move-assignment from rvalue temporary
std::cout << "Trying to move-assign A from xvalue\n";
a2 = std::move(a1); // move-assignment from xvalue
std::cout << "Trying to move-assign B\n";
B b1, b2;
std::cout << "Before move, b1.s = \"" << b1.s << "\"\n";
b2 = std::move(b1); // calls implicit move assignment
std::cout << "After move, b1.s = \"" << b1.s << "\"\n";
std::cout << "Trying to move-assign C\n";
C c1, c2;
c2 = std::move(c1); // calls the copy assignment operator
std::cout << "Trying to move-assign D\n";
D d1, d2;
// d2 = std::move(d1);
}
While executing a2 = std::move(a1) statement, the behaviour is different from executing the statement b2 = std::move(b1). In the below statement the b1.s is not becoming empty after the move operation while a1.s is becoming empty after move operation.
Can anyone tell what exactly is happening there?
One of the great (and constant) misconceptions about C++11 and rvalue references is that std::move does something to an object (or something on that order).
It doesn't. std::move really just casts its parameter to rvalue reference type and returns that. Anything done to the object happens in the move constructor, move assignment operator (etc.) based on the fact that the version that takes an rvalue reference is invoked (instead of one taking a value or lvalue reference).
As far as the specific question you asked goes, at least based on the comments in your code, you seem to have some misunderstandings. The comment on a2=std::move(a1); says you're doing a "move assignment from an xvalue". That's...misleading at best. An xvalue is a value that's going to eXpire immediately. It's pretty much for the return value from a function:
Foo &&bar() {
Foo f;
// ...
return f;
}
In this case, bar() is an xvalue because bar returns an rvalue reference to an object that expires (goes out of scope) as function finishes execution.
As far as the specific question you asked goes, I suspect it mostly comes down to a question of whether (and if so, exactly how) your standard library implements the move constructor for std::string. Just for example, when using g++ (4.9.1) I get the same result you do--b1.s contains test both before and after being used as the source of a move. On the other hand, if I use MS VC++ 14 CTP, I get b1.s="test" before the move and b1.s="" after the move. Although I haven't tested it, I'd expect results with Clang to be the same. In short, it looks like gcc's standard library doesn't really implement move assignment/construction for std::string (yet--at least as of v 4.9--I haven't looked at 5.0 yet).
Usually move assignment is implemented as a swap on std::string, so why should the string become empty since it's always initialized with "test"?
Where do you see that a1.s is becoming empty since there is no print of it?
I don't see any strange behavior here. Both are treated in the same way.
Suppose I have a class A. I have defined a copy constructor and an assignment operator overloading function. When I do
Class A;
Class B=A;
Then while defining Class B, is the copy constructor invoked or the assignment operator?
Thanks in advance.
EDIT:
Sorry, I mentioned wrong code. It should be:
A a;
A b=a;
IIRC T t = value invokes the copy constructor, you can verify that by outputting a string in the constructors to determine which method is used. IIRC when the declaration and assignment are on the same line, it is not called assignment but initialization.
On the other hand, what you've posted does not make sense, you cannot assign one type to another type, you can only assign to type instances.
EDIT: Even if you have a case of two different types (the context of your question is not clear on this one):
class A {};
class B {
public:
B(const A& other) { cout << "copy"; }
B& operator=(const A& other) { cout << "assign"; }
};
int main() {
A a;
B b = a; // copy con
B b1(a); // same as above
b = a; // assign op
}
Even then, when both the "copy constructor" and assignment operators take in another type, the copy constructor will still be invoked rather than the assignment operator.
Assuming you actually mean something like:
A a;
A b = a;
The copy constructor is invoked. The Standard allows = this special meaning in this usage.
Create a simple class with both, and debug what function is executed by setting a breakpoint in both. Then youll see, and youll also learn a little bit of debugging.
Let's try it out!
#include <iostream>
class A {
public:
A() {
std::cout << "default constructor\n";
}
A(const A& other) {
std::cout << "copy constructor\n";
}
A& operator=(const A& rhs) {
std::cout << "assignment operator\n";
return *this;
}
};
int main(int argc, char** argv) {
std::cout << "first declaration: ";
A a;
std::cout << "second declaration: ";
A b(a);
std::cout << "third declaration: ";
A c = a;
std::cout << "fourth declaration: ";
A d;
std::cout << "copying? ";
d = a;
return 0;
}
This prints:
first declaration: default constructor
second declaration: copy constructor
third declaration: copy constructor
fourth declaration: default constructor
copying? assignment operator
Working example here: http://codepad.org/DNCpqK2E
when you are defining a new object with assigning another object into it. It invokes copy constructor.
e.g,
Copy constructor call:
Class A;
Class B=A;
Assignment operator call:
Class A;
Class B;
B=A;
You can always test this, by writing a "print" statement in both the methods to find out which one is being called.
Hope it helped...
Sorry for the basic question, but I'm having trouble finding the right thing to google.
#include <iostream>
#include <string>
using namespace std;
class C {
public:
C(int n) {
x = new int(n);
}
~C( ) {
delete x;
}
int getX() {return *x;}
private:
int* x;
};
void main( ) {
C obj1 = C(3);
obj1 = C(4);
cout << obj1.getX() << endl;
}
It looks like it does the assignment correctly, then calls the destructor on obj1 leaving x with a garbage value rather than a value of 4. If this is valid, why does it do this?
If there is a class C that has a constructor that takes an int, is this code valid?
C obj1(3);
obj1=C(4);
Assuming C has an operator=(C) (which it will by default), the code is valid. What will happen is that in the first line obj1 is constructed with 3 as a the parameter to the constructor. Then on the second line, a temporary C object is constructed with 4 as a parameter and then operator= is invoked on obj1 with that temporary object as a parameter. After that the temporary object will be destructed.
If obj1 is in an invalid state after the assignment (but not before), there likely is a problem with C's operator=.
Update: If x really needs to be a pointer you have three options:
Let the user instead of the destructor decide when the value of x should be deleted by defining a destruction method that the user needs to call explicitly. This will cause memory leaks if the user forgets to do so.
Define operator= so that it will create a copy of the integer instead of a copy of the value. If in your real code you use a pointer to something that's much bigger than an int, this might be too expensive.
Use reference counting to keep track how many instances of C hold a pointer to the same object and delete the object when its count reaches 0.
If C contains a pointer to something, you pretty much always need to implement operator=. In your case it would have this signature
class C
{
public:
void operator=(const C& rhs)
{
// For each member in rhs, copy it to ourselves
}
// Your other member variables and methods go here...
};
I do not know enough deep, subtle C++ to explain the problem you are encountering. I do know, however, that it's a lot easier to make sure a class behaves the way you expect if you follow the Rule of Three, which the code you posted violates. Basically, it states that if you define any of the following you should define all three:
Destructor
Copy constructor
Assignment operator
Note as well that the assignment operator implementation needs to correctly handle the case where an object is assigned to itself (so-called "self assignment"). The following should work correctly (untested):
#include <iostream>
#include <string>
using namespace std;
class C {
public:
C(int n) {
x = new int(n);
}
C(const C &other): C(other.getX()) { }
~C( ) {
delete x;
}
void operator=(const C &other) {
// Just assign over x. You could reallocate if you first test
// that x != other.x (the pointers, not contents). The test is
// needed to make sure the code is self-assignment-safe.
*x = *(other.x);
}
int getX() {return *x;}
private:
int* x;
};
void main( ) {
C obj1 = C(3);
obj1 = C(4);
cout << obj1.getX() << endl;
}
Basically you are trying to re-implement a smart pointer.
This is not trivial to get correct for all situations.
Please look at the available smart pointers in the standard first.
A basic implementation (Which will fail under certain situations (copy one of the standard ones to get a better one)). But this should cover the basics:
class X
{
int* data;
public:
// Destructor obvious
~X()
{
delete data;
}
// Easy constructor.
X(int x)
:data(new int(x))
{}
// Copy constructor.
// Relatively obvious just do the same as the normal construcor.
// Get the value from the rhs (copy). Note A class is a friend of
// itself and thus you can access the private members of copy without
// having to use any accessor functions like getX()
X(X const& copy)
:data(new int(copy.x))
{}
// Assignment operator
// This is an example of the copy and swap idiom. This is probably overkill
// for this trivial example but provided here to show how it is used.
X& operator=(X const& copy)
{
X tmp(copy);
this->swap(tmp);
return this;
}
// Write a swap() operator.
// Mark it is as no-throw.
void swap(X& rhs) throws()
{
std::swap(data,rhs.data);
}
};
NEW:
What's happening is that your destructor has deallocated the memory allocated by the constructor of C(4). So the pointer you have copied over from C(4) is a dangling pointer i.e. it still points to the memory location of the deallocated memory
class C {
public:
C(int n) {
x = new int(n);
}
~C( ) {
//delete x; //Don't deallocate
}
void DeallocateX()
{
delete x;
}
int getX() {return *x;}
private:
int* x;
};
int main(int argc, char* argv[])
{
// Init with C(3)
C obj1 = C(3);
// Deallocate C(3)
obj1.DeallocateX();
// Allocate memory and store 4 with C(4) and pass the pointer over to obj1
obj1 = C(4);
// Use the value
cout << obj1.getX() << endl;
// Cleanup
obj1.DeallocateX();
return 0;
}
Be explicit about ownership of pointers! auto_ptr is great for this. Also, when creating a local don't do C obj1 = C(3) that creates two instances of C and initializes the first with the copy constructor of the second.
Heed The Guru.
class C {
public:
C(int n) : x(new int(n)) { }
int getX(){ return *x; }
C(const C& other) : x(new int(*other.x)){}
C& operator=(const C& other) { *x = *other.x; return *this; }
private:
std::auto_ptr<int> x;
};
int main() {
C obj1(3);
obj1 = C(4);
std::cout << obj1.getX() << std::endl;
}
When are you testing the value of obj1? Is it after you leave the scope?
In your example, obj1 is a stack object. That means as soon as you leave the function in which it defined, it gets cleaned up (the destructor is called). Try allocating the object on the heap:
C *obj1 = new C(3);
delete obj1;
obj1 = new C(4);