Copy Constructor and other questions

M

MSR

I have a couple of questions.

1. Copy Constructor.

class A {
private:
int a1;
double d1;
char *ptr;

public:
const A* operator=(const A* b)
{
memcpy(this, b, sizeof(A));
ptr = new char[100];
};

};

int main()
{
A *b = new b;
A *c=b;
.............
..........
};

Does C++ guarantee that my memcpy always make an exact duplicate of Object
'b' no matter how big the class is. Is this a general way of writing copy
constructors?


2. Null Reference. For example we have a function that searches a list and
returns a pointer to an object if it is found or NULL if it can't find the
object. How can I do this if I want to return a reference instead of a
pointer, without throwing exceptions?


3. This code is from FAQ lite.

class Point {
public:
static Point rectangular(float x, float y); // Rectangular coord's
static Point polar(float radius, float angle); // Polar coordinates
// These static methods are the so-called "named constructors"
...
private:
Point(float x, float y); // Rectangular coordinates
float x_, y_;
};

inline Point::point(float x, float y)
: x_(x), y_(y) { }

inline Point Point::rectangular(float x, float y)
{ return Point(x, y); }

inline Point Point::polar(float radius, float angle)
{ return Point(radius*cos(angle), radius*sin(angle)); }

int main()
{
Point p1 = Point::rectangular(5.7, 1.2); // Obviously rectangular
Point p2 = Point::polar(5.7, 1.2); // Obviously polar
...
}

Dumb question. Now who owns p1 and p2 and how can I delete them?

Thanks for your time and help
--MSR
 
V

Victor Bazarov

MSR said:
I have a couple of questions.

1. Copy Constructor.

class A {
private:

Everything is private by default in a class. No need to clutter your
code with unnecessary constructs.
int a1;
double d1;
char *ptr;

public:
const A* operator=(const A* b)
{
memcpy(this, b, sizeof(A));
ptr = new char[100];
};
^
This semicolon is superfluous.
};

int main()
{
A *b = new b;
A *c=b;

It would be so much easier if you just declared those as objects and
didn't busy yourself with 'new' or 'delete' for at least a while.
............
.........
};

Does C++ guarantee that my memcpy always make an exact duplicate of Object
'b' no matter how big the class is.

C++ guarantees NOTHING when it comes to C library functions. That's C's
job to guarantee those. And since C knows NOTHING about classes, the use
of memcpy with non-POD types is _undefined_.
Is this a general way of writing copy constructors?

Of course not. First of all what you wrote is an assignment operator
and not a copy constructor. Second, using memcpy with classes (as I
already mentioned) is undefined. Third, it is extremely dangerous even
if it were defined. Trust me, you don't want go around copying class
objects using memcpy. Just use copy construction semantics for all your
data. If it's a dynamic array, copy it by allocating and then by using
std::copy on it.

Also, class A as you wrote (a) does not copy the array pointed to by
the member 'ptr' (and instead just allocates it and leaves it alone)
and (b) lacks any other construction. Perhaps you didn't want to write
other [irrelevant] things, but when dynamic memory management is used,
the "rule of three" has to be followed (or else).
2. Null Reference.

No such thing exists.
For example we have a function that searches a list and returns a pointer
to an object if it is found or NULL if it can't find the object. How can I
do this if I want to return a reference instead of a pointer, without
throwing exceptions?

You can't.
3. This code is from FAQ lite.

class Point {
public:
static Point rectangular(float x, float y); // Rectangular coord's
static Point polar(float radius, float angle); // Polar coordinates
// These static methods are the so-called "named constructors"
...
private:
Point(float x, float y); // Rectangular coordinates
float x_, y_;
};

inline Point::point(float x, float y)
: x_(x), y_(y) { }

inline Point Point::rectangular(float x, float y)
{ return Point(x, y); }

inline Point Point::polar(float radius, float angle)
{ return Point(radius*cos(angle), radius*sin(angle)); }

int main()
{
Point p1 = Point::rectangular(5.7, 1.2); // Obviously rectangular
Point p2 = Point::polar(5.7, 1.2); // Obviously polar
...
}

Dumb question. Now who owns p1 and p2 and how can I delete them?

They are automatic variables and will be disposed of at the end of
the 'main' function body. Nobody "owns" them and they don't need to
be explicitly deleted. Only objects created by 'new' need to be
'delete'd.

What book are you reading that doesn't talk about copy construction
and automatic variables?

V
 
P

Phil Staite

MSR said:
class A {
private:
int a1;
double d1;
char *ptr;

public:
const A* operator=(const A* b)
{
memcpy(this, b, sizeof(A));
ptr = new char[100];
};

};

Does C++ guarantee that my memcpy always make an exact duplicate of Object
'b' no matter how big the class is. Is this a general way of writing copy
constructors?

Yes, memcpy makes an exact copy of the memory pointed to but...

NO, NO, NOOOOOOO This is not the general way of writing copy
constructors!!! Besides, what you coded is the assignment operator.
Well, sort of. Usually they deal with const references to the source
object, not pointers.

Consider these problems:

A alpha;
alpha = α // hint, think memory leak

Consider passing a pointer to a class derived from A??? IIRC 'this'
points to *all* the storage for the object, and I believe in most
implementations the first thing there is the vtbl pointer. So your
blind memcpy will step on the A's vtbl pointer and point it at the
derived class's vtbl. Madness surely lies down this path... I know I
know, your example doesn't have virtual methods but I'm being general
here. And in general, memcpy is a bad idea in C++.

A more usual copy constructor for A would look something like:

A( const A& src ) : a1(src.a1), d1(src.d1), ptr(NULL)
{
if(src.ptr != NULL)
{
ptr = new char[ std::strlen(src.ptr) + 1 ];
std::strcpy(ptr,src.ptr);
}
}

And an assignment operator would look like:

A& operator=( const A& src )
{
if( &src != this ) // check for self-assignment
{
a1 = src.a1;
d1 = src.d1;
delete[] ptr;
if( src.ptr == NULL )
ptr = NULL;
else
{
ptr = new char[ std::strlen(src.ptr) + 1 ];
std::strcpy(ptr,src.ptr);
}
}
return *this;
}

2. Null Reference. For example we have a function that searches a list and
returns a pointer to an object if it is found or NULL if it can't find the
object. How can I do this if I want to return a reference instead of a
pointer, without throwing exceptions?

Well, you can return a reference to NULL, but then the burden is on the
code making the call to remember to check and see if the & of the
reffered-to object is NULL. (blech)

Bite the bullet, throw exceptions.

Don't return references.

Create a default and plug it in, return that reference.

Have a static "blank" or default no-value-found object and return a
reference to it.
3. This code is from FAQ lite.

class Point {
public:
static Point rectangular(float x, float y); // Rectangular coord's
static Point polar(float radius, float angle); // Polar coordinates
// These static methods are the so-called "named constructors"
...
private:
Point(float x, float y); // Rectangular coordinates
float x_, y_;
};

inline Point::point(float x, float y)
: x_(x), y_(y) { }

inline Point Point::rectangular(float x, float y)
{ return Point(x, y); }

inline Point Point::polar(float radius, float angle)
{ return Point(radius*cos(angle), radius*sin(angle)); }

int main()
{
Point p1 = Point::rectangular(5.7, 1.2); // Obviously rectangular
Point p2 = Point::polar(5.7, 1.2); // Obviously polar
...
}

Dumb question. Now who owns p1 and p2 and how can I delete them?

The local scope within the main() function owns the objects. Short
answer - you don't delete them. The compiler generates code that
deletes them (off the stack, not the heap!) when the function
exits/returns. (or throws an exception)
 
S

Sep

1. That is not a copy constructor. A copy constructor is named the
same as the class, has an implicit (that must be implicit) return type
of void and gets a similar value to
class_name const &ob
as its only parameter.

What you have implemented is a copy-assignment operator which is what
is called when the class participates as an lvalue after it has been
constructed. To illustrate this
class_name cl = c; //Would call the copy constructor
cl = c; //Would call the copy-assignment operator


To clarify a bit more, copy constructors usually do not involve
memcpying the other ob to the this pointer (neither does the
copy-assignment operator for that matter). Normally, any
non-pointermembers are copied by value using normal assignment
statements and any pointer members are assigned new storage and the
contents of the other object's pointer copied over.

Also, just so you know, the test code, as you've implemented it, will
do a standard assignment between the two pointers when assigning one to
the other as the copy-assignment operator that you did implement takes
as its implicit first parameter an object of type A and not type A*.


2. If you're returning a pointer to an object if it is found, then why
would you declaring the function as reference and not pointer? I don't
quite understand what you're trying to accomplish with it.


3. p1 and p2 are both local variables owned by the main function and
are automatically deleted as they were allocated on the stack, that is,
they needn't be deleted through any special syntax.
 
V

Victor Bazarov

Phil Staite said:
MSR wrote:
[...]
2. Null Reference. For example we have a function that searches a list
and returns a pointer to an object if it is found or NULL if it can't
find the object. How can I do this if I want to return a reference
instead of a pointer, without throwing exceptions?

Well, you can return a reference to NULL, [..]

How?
 
S

Sep

Do note, MSR, that the test code for your first question would not even
invoke that copy assignment operator if it were attempting assignation
and not copy construction. You overloaded operator = for objects of
type A only and not A*, thus the assignation taking place is a standard
scalar object to scalar object assignation resulting in the second
pointer pointing to the same block of memory that the first is.
 
M

MSR

Victor Bazarov said:
MSR said:
I have a couple of questions.

1. Copy Constructor.

class A {
private:

Everything is private by default in a class. No need to clutter your
code with unnecessary constructs.
int a1;
double d1;
char *ptr;

public:
const A* operator=(const A* b)
{
memcpy(this, b, sizeof(A));
ptr = new char[100];
};
^
This semicolon is superfluous.
};

int main()
{
A *b = new b;
A *c=b;

It would be so much easier if you just declared those as objects and
didn't busy yourself with 'new' or 'delete' for at least a while.

I wrote this simple class purely for posting. So was lazy to really
implement
something that resembles my real problem. In my real problem I do need
pointers as I need to do dynamic allocation. So, I tried to put my problem
in simplest way , but it probably didn't look that good.
C++ guarantees NOTHING when it comes to C library functions. That's C's
job to guarantee those. And since C knows NOTHING about classes, the use
of memcpy with non-POD types is _undefined_.

I see your point. My question should have been, does C++ guarantees that
object's allocated
memory would be continuous? But, now I do understand the problems especially
if there are
virtual functions.
Is this a general way of writing copy constructors?

Of course not. First of all what you wrote is an assignment operator
and not a copy constructor. Second, using memcpy with classes (as I
already mentioned) is undefined. Third, it is extremely dangerous even
if it were defined. Trust me, you don't want go around copying class
objects using memcpy. Just use copy construction semantics for all your
data. If it's a dynamic array, copy it by allocating and then by using
std::copy on it.

Also, class A as you wrote (a) does not copy the array pointed to by
the member 'ptr' (and instead just allocates it and leaves it alone)
and (b) lacks any other construction. Perhaps you didn't want to write
other [irrelevant] things, but when dynamic memory management is used,
the "rule of three" has to be followed (or else).
2. Null Reference.

No such thing exists.
For example we have a function that searches a list and returns a pointer
to an object if it is found or NULL if it can't find the object. How can
I do this if I want to return a reference instead of a pointer, without
throwing exceptions?

You can't.
3. This code is from FAQ lite.

class Point {
public:
static Point rectangular(float x, float y); // Rectangular coord's
static Point polar(float radius, float angle); // Polar coordinates
// These static methods are the so-called "named constructors"
...
private:
Point(float x, float y); // Rectangular coordinates
float x_, y_;
};

inline Point::point(float x, float y)
: x_(x), y_(y) { }

inline Point Point::rectangular(float x, float y)
{ return Point(x, y); }

inline Point Point::polar(float radius, float angle)
{ return Point(radius*cos(angle), radius*sin(angle)); }

int main()
{
Point p1 = Point::rectangular(5.7, 1.2); // Obviously rectangular
Point p2 = Point::polar(5.7, 1.2); // Obviously polar
...
}

Dumb question. Now who owns p1 and p2 and how can I delete them?

They are automatic variables and will be disposed of at the end of
the 'main' function body. Nobody "owns" them and they don't need to
be explicitly deleted. Only objects created by 'new' need to be
'delete'd.

I see that question, in the context of the code, is really dumb.
Let me give modified code

class Point {
public:
static Point* instance();
private:
static Point* _instance;
Point();
float x_, y_;
};

inline Point* Point::instance()
{
if(_instance == 0){
_instance = new Point();
}
return _instance;
}

inline Point::point( )
: x_(0), y_(0) { }

Point* Point::_instance=0;

int main()
{
Point* p1 = Point::instance() ;
.......
}

Now who owns p1 and how can I delete it.
What book are you reading that doesn't talk about copy construction
and automatic variables?

Actually I am not reading any book. I know I should. I know C and
am working on C++ from that experience. I know C++ is different but then it
is similar too. I got Stroustrup's book and will start reading soon.

Thanks V for you reply
 
P

Phil Staite

Victor said:
Well, you can return a reference to NULL, [..]


How?


Not that any sane programmer would do this (but that apparently only
rules out about 10% of us)... I've seen some stupid...er "heroic"
things tried in order to fit into just the kinds of constraints the OP
mentioned - return a ref, no exceptions... IMHO that's a good time for
the designer/coder to "push back" on the requirements. But when they
can't/won't you end up with "stuff" like this:


#include<iostream>

class foo
{
public:
void ident()
{
std::cout << "My address is: " << static_cast<void*>(this) <<
std::endl;
}
};


foo& stupidFunction()
{
return *static_cast<foo*>(NULL);
}


int main(int argc, char* argv[])
{
stupidFunction().ident();
return 0;
}


And a really bad "contract" with the caller of the function that they
have to check that the reference they get back is in fact a real object.
Ugh!!!
 
P

Phil Staite

PS - I'm almost ashamed to post that dereference a cast of a NULL
code/construct. I don't want anyone to ever use it - so everyone forget
you ever saw it.

PPS - Drop the "almost" above...
 
M

MSR

Phil Staite said:
MSR said:
class A {
private:
int a1;
double d1;
char *ptr;

public:
const A* operator=(const A* b)
{
memcpy(this, b, sizeof(A));
ptr = new char[100];
};

};

Does C++ guarantee that my memcpy always make an exact duplicate of
Object 'b' no matter how big the class is. Is this a general way of
writing copy constructors?

Yes, memcpy makes an exact copy of the memory pointed to but...

NO, NO, NOOOOOOO This is not the general way of writing copy
constructors!!! Besides, what you coded is the assignment operator. Well,
sort of. Usually they deal with const references to the source object,
not pointers.

Consider these problems:

A alpha;
alpha = &alpha; // hint, think memory leak

Consider passing a pointer to a class derived from A??? IIRC 'this'
points to *all* the storage for the object, and I believe in most
implementations the first thing there is the vtbl pointer. So your blind
memcpy will step on the A's vtbl pointer and point it at the derived
class's vtbl. Madness surely lies down this path... I know I know, your
example doesn't have virtual methods but I'm being general here. And in
general, memcpy is a bad idea in C++.

A more usual copy constructor for A would look something like:

A( const A& src ) : a1(src.a1), d1(src.d1), ptr(NULL)
{
if(src.ptr != NULL)
{
ptr = new char[ std::strlen(src.ptr) + 1 ];
std::strcpy(ptr,src.ptr);
}
}

And an assignment operator would look like:

A& operator=( const A& src )
{
if( &src != this ) // check for self-assignment
{
a1 = src.a1;
d1 = src.d1;
delete[] ptr;
if( src.ptr == NULL )
ptr = NULL;
else
{
ptr = new char[ std::strlen(src.ptr) + 1 ];
std::strcpy(ptr,src.ptr);
}
}
return *this;
}

Thanks. I see the problems with memcpy. My main motivation for using
memcpy instead of copying member one by one was, my objects are
pretty big and I wanted avoid typing which by the way is error prone.
But it looks like there is no easy way out
Well, you can return a reference to NULL, but then the burden is on the
code making the call to remember to check and see if the & of the
reffered-to object is NULL. (blech)

Bite the bullet, throw exceptions.

Don't return references.

Create a default and plug it in, return that reference.

Have a static "blank" or default no-value-found object and return a
reference to it.

Ok. I didnt read this.
 
M

MSR

Sep said:
1. That is not a copy constructor. A copy constructor is named the
same as the class, has an implicit (that must be implicit) return type
of void and gets a similar value to
class_name const &ob
as its only parameter.

What you have implemented is a copy-assignment operator which is what
is called when the class participates as an lvalue after it has been
constructed. To illustrate this
class_name cl = c; //Would call the copy constructor
cl = c; //Would call the copy-assignment operator


To clarify a bit more, copy constructors usually do not involve
memcpying the other ob to the this pointer (neither does the
copy-assignment operator for that matter). Normally, any
non-pointermembers are copied by value using normal assignment
statements and any pointer members are assigned new storage and the
contents of the other object's pointer copied over.

Also, just so you know, the test code, as you've implemented it, will
do a standard assignment between the two pointers when assigning one to
the other as the copy-assignment operator that you did implement takes
as its implicit first parameter an object of type A and not type A*.

Thanks for the detailed explanation. I did confuse between copy constructor
and
copy assignmen operator
2. If you're returning a pointer to an object if it is found, then why
would you declaring the function as reference and not pointer? I don't
quite understand what you're trying to accomplish with it.

I am returning a pointer to the object found because I couldn't find a way
to
return a reference to that object. I was trying to see, if I could acheive
the same
result by returning reference instead of a pointer. Using a pointer I would
return
a NULL if object not found in the list and I wanted to learn how I could do
the
same if I were to return a reference instead of a pointer. But from the
previous
replies, it became clear to me that it cant be (except for a serious piece
of hack).
3. p1 and p2 are both local variables owned by the main function and
are automatically deleted as they were allocated on the stack, that is,
they needn't be deleted through any special syntax.

My question, in the context of the code was really dumb. Please see my first
reply
to Victor's post, where I had new code that shows exactly what I wanted to
know.

Thanks once again Sep.
 
A

Aslan Kral

haber iletisinde þunlarý said:
Phil Staite said:
MSR wrote:
[...]
2. Null Reference. For example we have a function that searches a list
and returns a pointer to an object if it is found or NULL if it can't
find the object. How can I do this if I want to return a reference
instead of a pointer, without throwing exceptions?

Well, you can return a reference to NULL, [..]

How?

Well, I use a technique to pass a null reference from time to time. If it
can be done, returning a null reference should also be possible.

class Y
{
....
};
class X
{
public:
Y& GetY()
{
if (some_error)
return *(Y*)0;
else
return *(new Y);
}
};

Then of course you would need to check if it is a null reference.

void myFunc()
{
Y& ry = X().GetY();
if ( &ry == 0 )
error_code;
}
 
R

Richard Cavell

{
...
};
class X
{
public:
Y& GetY()
{
if (some_error)
return *(Y*)0;
else
return *(new Y);
}
};

Hi,

I'm no C++ genius, but this code has to be "wrong". Even if it does
compile, it has to be a bad idea, and means that your code is inherently
unsafe. Surely the point of having references is not to allow things
like this.
void myFunc()
{
Y& ry = X().GetY();
if ( &ry == 0 )
error_code;
}

It's bad enough doing this sort of thing with pointers.
 
A

Aslan Kral

haber iletisinde sunlari said:
Hi,

I'm no C++ genius, but this code has to be "wrong". Even if it does
compile, it has to be a bad idea, and means that your code is inherently
unsafe. Surely the point of having references is not to allow things
like this.

You are right. It was just an exercise of returning a null reference. I
don't think anybody would write something like that.
It's bad enough doing this sort of thing with pointers.

Right but with pointers you should always consider the possibility for being
null.
 
V

Victor Bazarov

MSR said:
[...]
Let me give modified code

class Point {
public:
static Point* instance();
private:
static Point* _instance;
Point();
float x_, y_;
};

inline Point* Point::instance()
{
if(_instance == 0){
_instance = new Point();
}
return _instance;
}

inline Point::point( )
: x_(0), y_(0) { }

Point* Point::_instance=0;

int main()
{
Point* p1 = Point::instance() ;
.......
}

Now who owns p1 and how can I delete it.

This is a good question. Since Point::_instance, a copy of which you
are given by the Point::instance() function, is a private member of
the Point class, the Point class is the owner and it should delete it
when nobody else needs that instance. Now, how you (on behalf of the
Point class) determine that nobody needs it any longer is up to you.

Basically, you have an example of a singleton here. There are several
popular implementations of singletons, read about them and make your
pick.
Actually I am not reading any book. I know I should. I know C and
am working on C++ from that experience. I know C++ is different but then
it
is similar too. I got Stroustrup's book and will start reading soon.

Beware that it's really jam-packed with information and you may need
to work up quite a concentration to successfully digest it.

Good luck!

V
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,481
Members
44,900
Latest member
Nell636132

Latest Threads

Top