Jump to content
  • Advertisement
Sign in to follow this  
DangerDave

Dereferencing an object pointer (easy if you know the answer - C++)

This topic is 4494 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

OK, I create an object with : Obj* o = new Obj(); That allocates memory for an Obj on the heap and returns a pointer to the beginning of this memory area, yes? Then what does this return? a = *o; And specifically, what does this do: Obj b(); *o = b; ....? Cheers,

Share this post


Link to post
Share on other sites
Advertisement
a = *o;

If a is declared as an object of the same type as that pointed to by o then what is pointed at by o is shallow copied to a.

Obj b();

Initialises a b on the stack.

*o = b;

Copies what is pointed at by o to b.

Dave

Share this post


Link to post
Share on other sites
AHAH, a shallow copy, right, that was confusing me - I was wondering what there was left to point to, turns out nothing, it just copies... Cheers for that, most useful.

Share this post


Link to post
Share on other sites
On a similar note, are you aware of the difference between a shallow and deep copy of an object?

Dave

Share this post


Link to post
Share on other sites
Also note that:
Obj b();

will be parsed as a declaration of a function called "b", which takes no parameters and returns an "Obj".

Share this post


Link to post
Share on other sites
Quote:
Original post by Dave
On a similar note, are you aware of the difference between a shallow and deep copy of an object?

Dave


I don't! That is, i don't know if i know :)
Could you explain?

Share this post


Link to post
Share on other sites
Ha, yeah shallow copy copies an object and its variables, including pointers, but does not follow the pointers and copy objects that are pointed to.

Share this post


Link to post
Share on other sites
Quote:
Original post by Dave
On a similar note, are you aware of the difference between a shallow and deep copy of an object?

It's late, so I let some code do the talk here [smile]

class A {
int * someBuffer;
public:
A( size_t entries, int defaultValue = 0 ) : someBuffer( new int[entries] ) {
std::fill( someBuffer, someBuffer + entries, defaultValue );
}

~A() {
delete [] someBuffer;
}

// rest of the class - i.e. one read-only and one write operation:
int FrontItem() const {
return someBuffer[0];
}
// let's suppose this would modify "someBuffer" in some way
void SomeOperation() {
// stuff...
}
};

void thisWillCrash() {
// example of a shallow copy: "a" allocates "someBuffer"
A a( 10 );
// a bitwise copy is performed, b's "someBuffer" will point to the same memory
// as a's "someBuffer"
A b = a;

// now a and b get destroyed, but since both instances try to delete the same
// memory buffer, this will send the program to the Great Land Of Undefined
}

// suppose we want to avoid this. for any dynamically allocated object we have
// have two options to fight the above desaster - both involve creating a custom
// assignment operator and copy-constructor:

// 1) "copy-on-write" strategy - we keep the same data as the "original", but
// make our own copy if the client wants to modify it:

class Cow {
int * someBuffer;
bool isCopy; // <- this flag tells us, whether we "own" the memory
// we need to reset our data sometimes - see below
void ResetBuffer() {
// delete the data iff we created it
if ( !isCopy )
delete [] someBuffer;
}
// this method will create our own data buffer if required
void PrepareWriteAccess() {
if ( isCopy ) {
// allocate our own buffer
int * newBuffer = new int[ GetBufferSize() ];
// copy the data...
std::copy( someBuffer, someBuffer + GetBufferSize(), newBuffer );
// ...and apply changes
someBuffer = newBuffer;
isCopy = false;
}
}
public:
Cow( size_t entries, int defaultValue = 0 )
: someBuffer( new int[entries] ),
isCopy( false ) // the instance actually owns the buffer
{
std::fill( someBuffer, someBuffer + entries, defaultValue );
}

// copy constructor
Cow( Cow const & other )
: someBuffer( other.someBuffer ),
isCopy( true ) // this time, we don't own the memory
{
// do nothing here - the buffer already contains valid data
}

// assignment operator
Cow & operator = ( Cow const & other ) {
// make sure valid statements like "a = a;" don't cause any trouble
if ( *this != other ) {
ResetBuffer();
// make a "shallow" copy and remember that
someBuffer = other.someBuffer;
isCopy = true;
}
// by convention, the assignment operator returns a reference to the object
return *this;
}

// the destructor will only delete data that was allocated by this instance
~Cow() {
ResetBuffer();
}

// since we don't modify any data here, this stays the same as in A:
int FrontItem() const {
return someBuffer[0];
}
// here, we modify data, so we need to check whether that's ok:
void SomeOperation() {
PrepareWriteAccess();
// stuff...
}

};

// 2) deep-copy strategy: always create instance data
class DeepCopy {
int * someBuffer;
public:
DeepCopy( size_t entries, int defaultValue = 0 ) : someBuffer( new int[entries] ) {
std::fill( someBuffer, someBuffer + entries, defaultValue );
}

DeepCopy( DeepCopy const & other ) : someBuffer( new int[ other.GetBufferSize() ] ) {
// copy the data
std::copy( other.someBuffer, other.someBuffer + other.GetBufferSize(), someBuffer );
}

DeepCopy & operator = ( DeepCopy const & other ) {
if ( *this != other ) {
delete [] someBuffer;
someBuffer = new int[ other.GetBufferSize() ];
// copy the data
std::copy( other.someBuffer, other.someBuffer + other.GetBufferSize(), someBuffer );
}
return *this;
}

// safe - the data was always created by this very instance
~DeepCopy() {
delete [] someBuffer;
}

// rest of the class - i.e. one read-only and one write operation:
int FrontItem() const {
return someBuffer[0];
}
// let's suppose this would modify "someBuffer" in some way
void SomeOperation() {
// stuff...
}
};


Both strategies have their pro's and con's. If it's costly to create a new state (or per-instance data if you will) and the state is likely to stay unchanged, Copy-On-Write seems reasonable.

By default, the compiler will generate copy contructors and assignment operators that perform shallow (i.e. bitwise) copies. So whenever your class contains dynamically allocated data or resources, make sure to have a custom copy contructor and assignment operator and choose a copy strategy that fits the usage pattern.

HTH,
Pat.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!