Reg. copy constructor

C

csudha

Hi all,
Can you please explain me the usage of copy constructor and how do we use it.
Give me some example.
Regards,
Sudha.
 
M

Michael Mair

csudha said:
Hi all,
Can you please explain me the usage of copy constructor and how do we use it.
Give me some example.

This is comp.lang.c, you are probably looking for comp.lang.c++
In C, there are (a priori) no constructors.
Before asking in comp.lang.c++, have a look at their FAQ before
asking the question.


Cheers
Michael
 
I

infobahn

csudha said:

Hello. I note from the other responses to your article that some people
have very funny ideas about topicality. Oh well, can't be helped.
Can you please explain me the usage of copy constructor and how do we use it.

Of course. Glad to oblige.

We use a copy constructor when we wish to create a new object that is
an exact copy of an existing object. This is particularly useful in
situations where we don't wish to expose the inner data of the
object ("data hiding"), or where our object contains pointers to
dynamic data (so that merely duplicating the object representation
of the object would create a danger of a "dangling pointer" when we
are cleaning up).
Give me some example.

Sure. The following example has been compiled and tested under
bcc32 (Borland C++ 5.3, invoked in topical mode) and gcc (again
in topical mode), and gave no diagnostics under either compiler
(under gcc, the flags -W -Wall -ansi -pedantic -O2 were used).

The program's output can be found at the end of this reply.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct T_
{
int this;
int that;
char *theother;
};

/* helper routine for a "deep copy" */
char *sduplicate(const char *s)
{
char *new = NULL;
if(s != NULL)
{
new = malloc(strlen(s) + 1);
if(new != NULL)
{
strcpy(new, s);
}
}

return new;
}

typedef struct T_ T;

/* first, a destructor */
void TDestroy(T **old)
{
if(old != NULL)
{
if(*old != NULL)
{
free((*old)->theother);
free(*old);
*old = NULL;
}
}
}

/* now, an ordinary constructor */
T *TCreate(int this, int that, const char * theother)
{
T *new = malloc(sizeof *new);
if(new != NULL)
{
new->this = this;
new->that = that;
new->theother = sduplicate(theother);
if(new->theother == NULL)
{
/* if we can't build it properly,
don't build it at all! */
TDestroy(&new);
}
}
return new;
}

/* now we can code a nice simple copy constructor */
T *TCreateCopy(const T* old)
{
return TCreate(old->this, old->that, old->theother);
}

int TModifyString(T *p, const char *new)
{
int rv = 1; /* error */
if(p != NULL && new != NULL)
{
char *q = sduplicate(new);
if(q != NULL)
{
free(p->theother);
p->theother = q;
rv = 0; /* success */
}
}

return rv;
}

/* proof of purchase */
int TPrint(FILE *fp, T *p)
{
int rv = 0;
if(fp != NULL && p != NULL)
{
rv = fprintf(fp,
"%d %d %s\n",
p->this,
p->that,
p->theother);
}
return rv;
}

/* test driver */
int main(void)
{
T *p = TCreate(123, 456, "hello, world");
if(p != NULL)
{
T *q = TCreateCopy(p);
if(q != NULL)
{
fputs("p = ", stdout);
TPrint(stdout, p);
fputs("q = ", stdout);
TPrint(stdout, q); /* show that the copy worked */
puts("Modifying p now");
if(TModifyString(p, "goodbye, world") == 0)
{
fputs("p = ", stdout);
TPrint(stdout, p);
fputs("q = ", stdout);
TPrint(stdout, q); /* show that q is unaffected by the change
to p, ie a "deep copy" was done */
}
TDestroy(&q);
}
TDestroy(&p);
}
return 0;
}

The output from this program is:

p = 123 456 hello, world
q = 123 456 hello, world
Modifying p now
p = 123 456 goodbye, world
q = 123 456 hello, world


HTH. HAND.
 
M

Michael Mair

infobahn said:
Hello. I note from the other responses to your article that some people
have very funny ideas about topicality. Oh well, can't be helped.

I did not say that it was off-topic and did not claim that there
was no way to have constructors in C...
The OP's request just pointed in the direction C++.

Of course. Glad to oblige.

We use a copy constructor when we wish to create a new object that is
an exact copy of an existing object. This is particularly useful in
situations where we don't wish to expose the inner data of the
object ("data hiding"), or where our object contains pointers to
dynamic data (so that merely duplicating the object representation
of the object would create a danger of a "dangling pointer" when we
are cleaning up).

IMO, the second case is the more important one -- and the one where
people find out that some things do not work automagically even
in object oriented languages.

Sure. The following example has been compiled and tested under
bcc32 (Borland C++ 5.3, invoked in topical mode) and gcc (again
in topical mode), and gave no diagnostics under either compiler
(under gcc, the flags -W -Wall -ansi -pedantic -O2 were used).

The program's output can be found at the end of this reply.
[snip: Nice example]

I now would like to be edified by your topical reply to the
OP's other request :)


Cheers
Michael
 
I

infobahn

Michael said:
I did not say that it was off-topic and did not claim that there
was no way to have constructors in C...
The OP's request just pointed in the direction C++.

Please forgive my gentle tease.
IMO, the second case is the more important one -- and the one where
people find out that some things do not work automagically even
in object oriented languages.

I think they're both important, but then I'm quite a fan of data hiding.
[snip: Nice example]

I now would like to be edified by your topical reply to the
OP's other request :)

My wish is your command. Or whatever.

Refresh. (But prepare to be disappointed. I didn't spend as much
time on the second one.)
 
E

E. Robert Tisdale

infobahn said:
The following example has been compiled and tested
under bcc32 (Borland C++ 5.3, invoked in topical mode)
and gcc (again in topical mode)
and gave no diagnostics under either compiler
(under gcc, the flags -W -Wall -ansi -pedantic -O2 were used).

The program's output can be found at the end of this reply.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct T_
{
int this;
int that;
char *theother;
};

/* helper routine for a "deep copy" */
char *sduplicate(const char *s)
{
char *new = NULL;
if(s != NULL)
{
new = malloc(strlen(s) + 1);
if(new != NULL)
{
strcpy(new, s);
}
}

return new;
}

typedef struct T_ T;

/* first, a destructor */
void TDestroy(T **old)
{
if(old != NULL)
{
if(*old != NULL)
{
free((*old)->theother);
free(*old);
*old = NULL;

This may seem like a good idea
but it will only cause you trouble.
}
}
}

/* now, an ordinary constructor */
T *TCreate(int this, int that, const char * theother)
{
T *new = malloc(sizeof *new);
if(new != NULL)
{
new->this = this;
new->that = that;
new->theother = sduplicate(theother);
if(new->theother == NULL)
{
/* if we can't build it properly,
don't build it at all! */
TDestroy(&new);
}
}
return new;
}

Actually, you have implemented new and delete
not create and destroy.
/* now we can code a nice simple copy constructor */
T *TCreateCopy(const T* old)
{
return TCreate(old->this, old->that, old->theother);
}

int TModifyString(T *p, const char *new)
{
int rv = 1; /* error */
if(p != NULL && new != NULL)
{
char *q = sduplicate(new);
if(q != NULL)
{
free(p->theother);
p->theother = q;
rv = 0; /* success */
}
}

return rv;
}

/* proof of purchase */
int TPrint(FILE *fp, T *p)
{
int rv = 0;
if(fp != NULL && p != NULL)
{
rv = fprintf(fp,
"%d %d %s\n",
p->this,
p->that,
p->theother);
}
return rv;
}

/* test driver */
int main(void)
{
T *p = TCreate(123, 456, "hello, world");
if(p != NULL)
{
T *q = TCreateCopy(p);
if(q != NULL)
{
fputs("p = ", stdout);
TPrint(stdout, p);
fputs("q = ", stdout);
TPrint(stdout, q); /* show that the copy worked */
puts("Modifying p now");
if(TModifyString(p, "goodbye, world") == 0)
{
fputs("p = ", stdout);
TPrint(stdout, p);
fputs("q = ", stdout);
TPrint(stdout, q); /* show that q is unaffected by the change
to p, ie a "deep copy" was done */
}
TDestroy(&q);
}
TDestroy(&p);
}
return 0;
}

Here is a simpler design:
> cat T.h
#ifndef GUARD_T_H
#define GUARD_T_H 1

// public interface
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define new C_new
#define this C_this

typedef struct T {
int this;
int that;
char* theother;
} T;

// destructor
inline static
void T_destroy(const T* old) {
if (old != NULL) {
free(old->theother);
}
}

inline static
void T_delete(const T* old) {
if (old != NULL) {
T_destroy(old);
}
free((void*)old);
}

// explicit [pseudo] constructor
T T_create(int this, int that, const char* const theother);

T* T_new(int this, int that, const char* const theother);

// copy constructor
inline static
T T_clone(const T* const old) {
return T_create(old->this, old->that, old->theother);
}

T* T_modify(T* const p, const char* const new);

// proof of purchase
inline static
int T_print(FILE *fp, const T* const p) {
int rv = 0;
if (fp != NULL && p != NULL) {
rv = fprintf(fp,
"%d %d %s\n",
p->this,
p->that,
p->theother);
}
return rv;
}

#endif//GUARD_T_H
> cat T.c
// [private] implementation
#include "T.h"

// [private] "deep copy" helper function
inline static
char *sduplicate(const char* const s) {
char* new = NULL;
if (s != NULL) {
new = (char*)malloc(strlen(s) + 1);
if (new != NULL) {
strcpy(new, s);
}
}
return new;
}

// [private] initializer
inline static
T* T_initialize(T* new,
int this, int that, const char* const theother) {
if (new != NULL) {
new->this = this;
new->that = that;
new->theother = sduplicate(theother);
}
return new;
}

// explicit [pseudo] constructor
T T_create(int this, int that, const char* const theother) {
T new;
T_initialize(&new, this, that, theother);
return new;
}

T* T_new(int this, int that, const char* const theother) {
T *new = (T*)malloc(sizeof *new);
if (new != NULL) {
T_initialize(new, this, that, theother);
}
return new;
}

T* T_modify(T* const p, const char* const new) {
if (p != NULL) {
free((void*)(p->theother));
p->theother = sduplicate(new);
}
return p;
}
> cat main.c
#include "T.h"

// test driver
int main(int argc, char* argv[]) {
T p = T_create(123, 456, "hello, world");
T q = T_clone(&p);
fputs("p = ", stdout);
T_print(stdout, &p);
fputs("q = ", stdout);
T_print(stdout, &q); // Show that the copy worked.
puts("Modifying p now");
T_modify(&p, "goodbye, world");
fputs("p = ", stdout);
T_print(stdout, &p);
fputs("q = ", stdout);
T_print(stdout, &q); // Show that q is unaffected
// by the change to p
// i.e. a "deep copy" was done.
T_destroy(&q);
T_destroy(&p);
return 0;
}
> gcc -Wall -std=c99 -pedantic -o main main.c T.c
> ./main
p = 123 456 hello, world
q = 123 456 hello, world
Modifying p now
p = 123 456 goodbye, world
q = 123 456 hello, world
> ln -s T.c T.cpp
> ln -s main.c main.cpp
> g++ -Wall -ansi -pedantic -o main main.cpp T.cpp
> ./main
p = 123 456 hello, world
q = 123 456 hello, world
Modifying p now
p = 123 456 goodbye, world
q = 123 456 hello, world
 
I

infobahn

E. Robert Tisdale said:
This may seem like a good idea
but it will only cause you trouble.

It has never yet done so.

Actually, you have implemented new and delete
not create and destroy.

No, I implemented TCreate() and TDestroy(). The clue is in the name
given to the function. That tells you what function is being
implemented.
Had I wished to implement a function called new() or delete(), I would
have used the name new() or delete().

Here is a simpler design:

....which failed to compile on my C compiler, and which contained
some utterly pointless code. It is probably true that your version
will work in C99, if we ever get it. But so will mine, and my
version /also/ works in C90.
 
E

E. Robert Tisdale

infobahn said:
It is probably true that your version will work in C99,
if we ever get it.

I hope that you get it soon.
I would hate to see you left behind in the previous century.
 
I

infobahn

E. Robert Tisdale said:
I hope that you get it soon.

And I hope that /you/ get it soon. You don't have it yet.
I would hate to see you left behind in the previous century.

When C99 is as widely available as C89, I will cheerfully start
using it. At present, there don't seem to be any conforming C99
implementations. Nevertheless, I write my code so that it is
legal in *both* flavours, so that I'll be ready to move to C99
seamlessly when the time comes.
 
C

CBFalconer

infobahn said:
And I hope that /you/ get it soon. You don't have it yet.


When C99 is as widely available as C89, I will cheerfully start
using it. At present, there don't seem to be any conforming C99
implementations. Nevertheless, I write my code so that it is
legal in *both* flavours, so that I'll be ready to move to C99
seamlessly when the time comes.

+-------------------+ .:\:\:/:/:.
| PLEASE DO NOT | :.:\:\:/:/:.:
| FEED THE TROLLS | :=.' - - '.=:
| | '=(\ 9 9 /)='
| Thank you, | ( (_) )
| Management | /`-vvv-'\
+-------------------+ / \
| | @@@ / /|,,,,,|\ \
| | @@@ /_// /^\ \\_\
@x@@x@ | | |/ WW( ( ) )WW
\||||/ | | \| __\,,\ /,,/__
\||/ | | | jgs (______Y______)
/\/\/\/\/\/\/\/\//\/\\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
==============================================================
 
M

Michael Mair

[Do not feed the trolls]

In this case ERT posted something useful or at least worth
constructive discussion; making him troll again by recapping
all the old stuff certainly is not his fault alone.


Cheers
Michael
 

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

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top