Here is the code first, it comes from 'Ruminations on C++' chapter 10
// TestCode.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <string>
#include <conio.h>
using namespace std;
class P_Node
{
friend class Picture;
protected:
P_Node() : use(1)
{
}
virtual ~P_Node()
{
}
private:
int use;
};
class Picture
{
friend Picture frame(const Picture&);
public:
Picture() : p(new P_Node)
{
cout << "Constructor\t" << "Picture::Picture()" << "\tcalled" << endl;
cout << "Picture p count\t" << p->use << endl;
}
Picture(const Picture& orig) : p(orig.p)
{
cout << "Copy Constructor\t" << "Picture::Picture(const Picture&)" << "\tcalled" << endl;
cout << "Picture p count\t" << p->use << endl;
orig.p->use++;
}
~Picture()
{
cout << "Destructor\t" << "Picture::~Picture()" << "\tcalled" << endl;
cout << "Picture p count before decrease\t" << p->use << endl;
if(--p->use == 0)
{
cout << "Picture p count after decrease\t" << p->use << endl;
cout << "Deleted" << endl;
delete p;
}
}
Picture& operator=(const Picture& orig)
{
cout << "operator=\t" << "Picture& Picture::operator=(const Picture& orig)" << "\tcalled" << endl;
cout << "Picture p count before decrease\t" << p->use << endl;
orig.p->use++;
if(--p->use == 0)
{
cout << "Picture p count after decrease\t" << p->use << endl;
delete p;
}
p = orig.p;
return *this;
}
private:
Picture(P_Node* p_node) : p(p_node)
{
// Why not p_node->use++?
cout << "Picture::Picture(P_Node* p_node)\tcalled" << endl;
}
P_Node *p;
};
class Frame_Pic : public P_Node
{
friend Picture frame(const Picture&);
private:
Frame_Pic(const Picture& pic) : p(pic)
{
cout << "Frame_Pic::Frame_Pic(const Picture& orig)" << "\tcalled" << endl;
}
Picture p;
};
Picture frame(const Picture& pic)
{
return new Frame_Pic(pic);
}
int main(int argc, char* argv[])
{
Picture my_pic;
frame(my_pic);
return 0;
}
The result is:
Constructor Picture::Picture() called
Picture p count 1
Copy Constructor Picture::Picture(const Picture&) called
Picture p count 1
Frame_Pic::Frame_Pic(const Picture& orig) called
Picture::Picture(P_Node* p_node) called
Destructor Picture::~Picture() called
Picture p count before decrease 1
Picture p count after decrease 0
Deleted
Destructor Picture::~Picture() called
Picture p count before decrease 2
Destructor Picture::~Picture() called
Picture p count before decrease 1
Picture p count after decrease 0
Deleted
I have two questions about this code:
Why is the copy constructor called before Frame_Pic's Constructor? In my mind, the copy constructor is called because frame(my_pic) is returning a Picture by value. But that should be called after Frame_Pic's Constructor.
In Picture::Picture(P_Node* p_node), why not increase the use count? isn't this creating a new Picture?
Thanks for any help.
I'm using VC6 under Windows XP.
1, Why is the Copy Constructor called before Frame_Pic's Constructor?
Because the p member is being copy-constructed in the initialization list of Frame_pic's constructor. The initialization list runs before the constructor's body is entered.
In my mind, the Copy Constructor is called because frame(my_pic) is returning a Picture by value. But that should be called after Frame_Pic's Constructor.
frame() is declared to return a Picture instance by value, but it is coded to return a Frame_pic* instead. Frame_pic derives from P_node, and Picture has a constructor that accepts a P_node*, and that constructor is accessible to frame() so the compiler allows it.
2, In Picture::Picture(P_Node* p_node), why not increase the use count? isn't this creating a new Picture?
The use count is on P_node, not Picture. The Picture that frame() returns owns the Frame_pic that frame() creates, whose use count member is already 1 by the Frame_pic constructor. That is why that Picture constructor does not increment the use count - it is already at the correct value.
The Frame_pic contains its own Picture that is copy-constructed from another Picture, so that Picture constructor needs to increment the use count of the original Picture.
The copy constructor is invoked by Frame_Pic's constructor (it's invoked by the initializer : p(pic)). However Frame_Pic's constructor doesn't print until after all initializers have been run.
Because the intended use of the constructor is not documented, it's hard to say. It may be a bug, or it may be 'attach semantics' - that is, it may be considering the case where you take manual control of the P_Node*, then later give it back. However attach semantics is unlikely, as there's no corresponding detach mechanism to return the pointer and clear it without decrementing the refcount. So, most likely a bug.
Note that while this sort of manual reference counting can be good as a learning exercise, modern C++ code generally uses smart pointers (eg, std::shared_ptr or boost::shared_ptr, invasive_ptr, etc) to automate the process.
Frame_Pic(const Picture& pic) : p(pic)
{
cout << "Frame_Pic::Frame_Pic(const Picture& orig)" << "\tcalled" << endl;
}
You initializing 'p' using its copy constructor 'p(pic)', hence it gets called in the order you see
Related
I have the following piece of code. I expected it to fail, i.e. I thought that move constructor would execute when entering 'send' function and, when trying to call 'send' again this should be an invalid operation ('a' is no longer a valid object because it was moved from). But somehow this code executes without any problem.
Output shows that move constructor is not even executed.
#include <iostream>
using namespace std;
struct A {
int *ptr;
A() { cout << "ctor A" << endl; ptr = new int(1); }
A(A&& o) { cout << "move ctor" << endl; ptr = o.ptr; o.ptr = nullptr; }
~A() { cout << "dtor" << endl; delete ptr; }
void send() { cout << *ptr << endl; }
};
bool send(A&& a, int i)
{
if (i == 0) {
cout << "returning" << endl;
return false;
}
cout << "sending" << endl;
a.send();
return true;
}
int main()
{
A a;
if(!send(move(a),0))
send(move(a),1);
}
Output:
ctor A
returning
sending
1
dtor
However when when I change the 'send' method to accept A objects by value, the problem appears exactly how I had imagined. Move ctor is called, and when second time 'send' is called, 'a' is not valid, we have segmentation fault.
bool send(A a, int i)
{
if (i == 0) {
cout << "returning" << endl;
return false;
}
cout << "sending" << endl;
a.send();
return true;
}
Result:
ctor A
move ctor
returning
dtor
move ctor
sending
Segmentation fault
So, move constructor is only called when moved object is passed by value. Ok, I got it.
My question however is this: is it safe to declare function 'send' this way, i.e. to accept parameters by r-value reference and then call it with moved object multiple times? I know that std::move doesn't really move anything, only creates r-value reference, but anyhow: is it safe? Or, in other words, is there a guideline which says "Don't do this"?
[https://wandbox.org/permlink/R5spfEGI7WZR9lwR][1]
If you actually move the object within the send function, then you will see the behavior you expect (segmentation fault when a.send is called). For example:
bool send(A &&a, int i)
{
A b = move(a);
if (i == 0) {
cout << "returning" << endl;
return false;
}
cout << "sending" << endl;
a.send();
return true;
}
This is the full example (source book: C++ From Ground Up, 3rd Edition, page 219-320):
class sample {
char *s;
public:
sample(); // normal constructor
sample(const sample &ob); // copy constructor
~sample( ) { cout << "s: " << s <<" ,Freeing s\n"; if(s) delete [] s;}
void show() { cout << s << "\n"; }
void set(char *str);
sample operator=(const sample &ob); // overload assignment
};
// Normal constructor.
sample::sample() {
s = new char('\0'); // s points to a null string.
cout << "Normal constructor: s: " << strlen(s) << endl;
}
// Copy constructor.
sample::sample(const sample &ob) {
cout << "Copy constructor: ob.s: "<< ob.s << " ,strlen(ob.s): " << strlen(ob.s) << "\n";
s = new char[strlen(ob.s)+1];
strcpy(s, ob.s);
}
// Load a string.
void sample::set(char *str) {
s = new char[strlen(str)+1];
strcpy(s, str);
}
// Overload assignment operator.
sample sample::operator=(const sample &ob) {
/* If the target memory is not large enough
then allocate new memory. */
cout << "operator= strlen(ob.s): " << strlen(ob.s) << " ,strlen(s): " << strlen(s) << endl;
if(strlen(ob.s) > strlen(s)) {
cout << "operator= Larger memory of target object. Deleting current...\n";
delete [] s;
s = new char[strlen(ob.s)+1];
}
strcpy(s, ob.s);
return *this;
}
// Return an object of type sample.
sample input() {
char instr[80];
static sample str;
cout << "Enter a string: ";
cin >> instr;
str.set(instr);
return str;
}
int main() {
sample ob;
// assign returned object to ob
ob=input(); // This is now OK
ob.show();
return 0;
}
However I do not get why TWO times copy constructor is called.
(output once code is ran)
Normal constructor: s:
Normal constructor: s:
Enter a string: Hello
Copy constructor: ob.s: Hello ,strlen(ob.s): 5
operator= strlen(ob.s): 5 strlen(s): 0
operator= Larger memory of target object. Deleting current...
Copy constructor: ob.s: Hello ,strlen(ob.s): 5
s: Hello, Freeing s
s: Hello, Freeing s
Hello
s: Hello, Freeing s
s: Hello, Freeing s
I know it is called when input() function returns, and create temporary object (by calling copy constructor), but I do not get why second time since, as much as I know (but maybe I am wrong) copy constructors are NOT called for assignment operations, but it looks like, despite of that, when return *this; is called (when overloaded operator returns value), copy constructor is called?
What did I missed?
Thankx
The code is really terrible. Not to mention other bugs, here is why copy constructor is called twice.
First time it's called when an object is returned from input() since it's static and returned by value, so no RVO can be applied.
The second call happens as a result of return *this; in operator=() because for some reason it's returning an object also by value:
sample operator=(const sample &ob);
// ^^^
I have the following issue with reference parameters:
When we have a function with reference parameters, the compiler will automatically pass to that function, the address of any argument it is called with.
Example (with object):
class sample {
char *s;
public:
sample(); // normal constructor
sample(const sample &ob); // copy constructor
~sample( ) { if(s) delete [] s; cout << "Freeing s\n"; }
void show() { cout << s << "\n"; }
void set(char *str);
};// Definition will be excluded from here`
and we have a function with reference parameters of this class instance,
like:
void funtionWithRef(sample &kk); // declaration
void funtionWithRef(sample &sam){ // definition
sam.show();
}
and one function with return object of type sample:
sample functionReturnSample(); //declaration
sample functionReturnSample(){ // definition
sample sam;
sam.set("test sample");
return sam;
}
Now, when we do:
int main() {
sample temp = functionReturnSample();
funtionWithRef(temp);
return 0;
}
It works perfect. When we put temp object as an argument to funtionWithRef, compiler pass address of that object to the function.
But WHY it does not work, if we do NOT first assign a returning value of functionReturnSample to the instance, but directly put that method as an argument like :
funtionWithRef(functionReturnSample());
Why is this different, when we are doing the same thing, and according to some books I consulted, whit SHOULD
EDIT
#user657267
This is the full example (source book: C++ From Ground Up, 3rd Edition, page 219-320):
class sample {
char *s;
public:
sample(); // normal constructor
sample(const sample &ob); // copy constructor
~sample( ) { cout << "s: " << s <<" ,Freeing s\n"; if(s) delete [] s;}
void show() { cout << s << "\n"; }
void set(char *str);
sample operator=(sample &ob); // overload assignment
};
// Normal constructor.
sample::sample() {
s = new char('\0'); // s points to a null string.
cout << "Normal constructor: s: " << strlen(s) << endl;
}
// Copy constructor.
sample::sample(const sample &ob) {
cout << "Copy constructor: ob.s: "<< ob.s << " ,strlen(ob.s): " << strlen(ob.s) << "\n";
s = new char[strlen(ob.s)+1];
strcpy(s, ob.s);
}
// Load a string.
void sample::set(char *str) {
s = new char[strlen(str)+1];
strcpy(s, str);
}
// Overload assignment operator.
sample sample::operator=(sample &ob) {
/* If the target memory is not large enough
then allocate new memory. */
cout << "operator= strlen(ob.s): " << strlen(ob.s) << " ,strlen(s): " << strlen(s) << endl;
if(strlen(ob.s) > strlen(s)) {
cout << "operator= Larger memory of target object. Deleting current...\n";
delete [] s;
s = new char[strlen(ob.s)+1];
}
strcpy(s, ob.s);
return *this;
}
// Return an object of type sample.
sample input() {
char instr[80];
static sample str;
cout << "Enter a string: ";
cin >> instr;
str.set(instr);
return str;
}
int main() {
sample ob;
// assign returned object to ob
ob=input(); // This is now OK
ob.show();
return 0;
}
This wont compile, and reports error:
**error: no match for ‘operator=’ (operand types are ‘sample’ and ‘sample’)**
So it is copy/past of the code from the mentioned book. You can check please.
However I figureout if I specify overloaded = operator arguments to be const like:
sample operator=(const sample &ob); // overload assignment
Then it DOES work.
However, what is bothering me is, now when I have runnable code, I do not get why TWO times copy constructor is called.
I know it is called when input() function returns, and create temporary object, but I do not get why second time since, as much as I know (but maybe I am wrong) copy constructors are NOT called for assignment operations (same Book, pages 291-292), but it looks like, despite of that, when return *this; is called (when overloaded operator returns value), copy constructor is called?
So what is about that ?
Thankx
I have a question regarding the following code, which crashes. I am creating a local variable in testfunction() and then pushing it (variable "y") into a list. This variable has a member pointer "b" of object type Ball. As I understand, this local variable "y" is on the stack, so its' destructor will be called after testfunction() is completed. Also, as I understand, a vector "copies" an object into its' list. From what I've learned, it is best practice to delete a pointer in the destructor if one exists in its' class. So, there is "delete b" in the destructor of Example.
The issue that I am having is that the object y.b is being destroyed at the completion of testfunction(). In main(), I am able to see the value of "name" and the address of "b", but the object "b" has already been deleted. I would like to avoid this.
I think there is an issue with the design of the code/use of pointers vs references, etc. Please guide me in the right direction, I am an idiot!
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Ball
{
public:
int a;
Ball()
{
a = 0;
}
~Ball()
{
cout << "destroyed Ball()" << endl;
}
};
class Example
{
public:
string name;
Ball* b;
Example()
{
name = "";
b = NULL;
}
~Example()
{
cout << "destroying Example()" << endl;
delete b;
}
};
void testfunction(vector<Example>& list)
{
cout << "entered testfunction1()" << endl;
Example y;
y.name = "myName";
y.b = new Ball();
y.b->a = 5;
cout << "y.b->a = " << y.b->a << endl;
list.push_back(y);
cout << "exit testfunction1()" << endl;
}
void testfunction2()
{
cout << "entered testfunction2()" << endl;
Example* y = new Example();
cout << "exit testfunction2()" << endl;
}
int main() {
vector<Example> list;
testfunction(list);
//testfunction2();
if(list[0].b == NULL)
cout << "b is null" << endl;
else
cout << "b is not null" << endl;
cout << list[0].name << endl;
cout << list[0].b << endl;
cout << "list[0].b->a = " << list[0].b->a << endl;
return 0;
}
Since class Example has a pointer member and it tries to own a dynamically allocated resource, it needs non-default copy operations, in other words, it needs user-defined copy constructor and assignment operator.
Inside testfunction, when you copy y into vector, both local y and y copied to the vector point to very same Ball object. The local y is destroyed at the end of the function and Ball is deleted. However, that deleted Ball still pointed by the y in vector
void testfunction(vector<Example>& list)
{
// ...
Example y;
y.name = "myName";
y.b = new Ball();
y.b->a = 5;
list.push_back(y);
// ...
} // <-- destructor for Example y is called and y.b is deleted
Define a copy constructor and an assignement operator for your class Example.
These shall copy properly your object (creating a duplicated Ball object) when pushed back on the vector.
Example(const Example& a)
{
name = a.name; // attention no dynamic allocation
cout << "copy" <<endl;
if (a.b) {
b = new Ball(*a.b); // create a new duplicated Ball
}
else b = NULL;
}
The problem in your example is that the default copy constructor is called when you pushback the object. It copies memberwise and so the pointer to Ball is copied, not the object pointed to.
Yet another alternative could be to replace your Ball* with shared_ptr<Ball> (and accordingly, new Ball with make_shared<Ball>() and the delete b of the object with a b.reset()). The principle is that this smart pointer keeps track of the number of time the object pointed to is used, so that it will not delete it twice, but only when its no longer used anywhere.
I have set up this example:
class UsefulClass {
public:
int id;
const bool operator< (const UsefulClass &other) const {
return this->id > other.id;
}
UsefulClass(int _id): id(_id) {
std::cout << "constructing " << id << std::endl;
}
~UsefulClass() {
std::cout << "destructing " << id << std::endl;
}
};
std::set<UsefulClass> set;
void create() {
UsefulClass object_1(1);
UsefulClass object_2(2);
set.insert(object_1);
set.insert(std::move(object_2));
std::cout << "create end" << std::endl;
}
int main() {
create();
std::cout << "main end" << std::endl;
}
I am expecting that the objects get destructed once when set gets deleted at the end of the program. But the objects get deleted twice:
constructing 1
constructing 2
create end
destructing 2
destructing 1
main end
destructing 1
destructing 2
Why is set.insert creating a copy here?
The objects in the set are different from the objects local to create(). The ones in the set are constructed using a copy constructor and move constructor, not the constructor UsefulClass(int), so you don't see their construction. The local objects get destroyed when the function create() returns, and then the objects in the set get destroyed at global cleanup after main ends.
object_1 and object_2 are created on stack and will be destroyed once the create() function ends. They need to be copied in the memory managed by set's allocator.
If you redefine the copy constructor, to trace its execution, you'll notice it is called at both inserts.
Rule of 3 applies to your case, if you print from dtor and want meaningful trace you should instrument copy (and maybe move) ctor also.
If you do that output will make sense and things should be properly paired.
Because your objects get copied on insertion into the set. Hence, when the create() function returns, the two local objects are destroyed. After main ends, the two copies that are in the set are destroyed, leading to the second pair of messages.
To illustrate whatever everybody has said before me, just create this simple example (it uses a new copy constructor for the set to use and uses a global variable to generate different ids each time a constructor is executed ---it's been tested, so you can put it in a file and compile):
#include <iostream>
#include <string>
#include <set>
using namespace std;
class UsefulClass {
static int instance;
public:
int id;
int i;
const bool operator<(const UsefulClass &other) const {
return id < other.id;
}
UsefulClass(int i){
id = instance++;
this->i = i;
cout << "constructing "
<< id
<< ":"
<< this->i
<< endl;
}
UsefulClass(const UsefulClass& other) {
id = instance++;
i = other.i;
cout << "constructing "
<< id
<< ":"
<< i
<< endl;
}
~UsefulClass(){
cout << "destructing "
<< id
<< ":"
<< i
<< endl;
}
};
int UsefulClass::instance = 0;
std::set<UsefulClass> myset;
void create() {
UsefulClass object_1(1);
UsefulClass object_2(2);
myset.insert(object_1);
/* please, explain what you mean with std::move, or which move
* have you used for the next statement. All i have is
* std::move(... ) for strings, but you have not defined
* string UsefulClass::operator string();
*/
myset.insert(/*std::move*/(object_2));
cout << "create end"
<< endl;
}
int main() {
create();
cout << "main end"
<< std::endl;
}
so you'll get a different instance id whenever you create a UsefulClass object and you'll see that when inserting into the set they are being copied as new instances. You'll see when each object is being created and when they are being deleted.
$ pru
constructing 0:1
constructing 1:2
constructing 2:1
constructing 3:2
create end
destructing 1:2
destructing 0:1
main end
destructing 2:1
destructing 3:2