Open Side Menu Go to the Top

02-13-2008 , 12:15 PM
In C++, what does the assignment operator '=' do for classes, assuming that I haven't overloaded it. For example, what would the following code do? I know it doesn't do what one would want it to do, but I can't remember exactly what goes on. I know Google is my friend, but all I got were a bunch of pages telling me how to overload the operator, which I already know. Thanks in advance to anyone who can help me out.

class X
{
...
}

.
.
.

X a;
X b;
a = b;
Quick C++ question Quote
Quick C++ question
150% up to $2,000 Welcome Bonus on CoinPoker
Join the action now
Daily Rewards • Splash Pots • CoinRaces
Quick C++ question
02-13-2008 , 12:37 PM
Quote:
Originally Posted by Dazarath
In C++, what does the assignment operator '=' do for classes, assuming that I haven't overloaded it. For example, what would the following code do? I know it doesn't do what one would want it to do, but I can't remember exactly what goes on. I know Google is my friend, but all I got were a bunch of pages telling me how to overload the operator, which I already know. Thanks in advance to anyone who can help me out.

class X
{
...
}

.
.
.

X a;
X b;
a = b;
It will just make a copy of all the binary data the class holds. This is fine if your class holds just basic data types or fixed length arrays, but will go wrong if the class contains any dynamically allocated memory or any classes which use dynamically allocated memory (ie: it won't invoke their copy constructor or assignment operator as expected). For example:

Code:
class X
{
  int I;
  char S[100];
}

.
.
.

X a;
X b;
a = b;
Is fine.

Code:
class X
{
  char* S;

  X() { S=new char[100]; }
  ~X() { delete [] S; } 
}

.
.
.

X a;
X b;
a = b;
Will go wrong.

Juk
Quick C++ question Quote
02-13-2008 , 12:44 PM
Another way to think of it is:

Code:
class X
{
...
}

.
.
.

X a;
X b;
a = b;
and
Code:
class X
{
...
}

.
.
.

X a;
X b;
memcpy((void*)a,(void*)b,sizeof(X));
are the same and if memcpy wouldn't work (because of dynamically allocated memory, file handles, etc) then neither will the basic compiler generated assignment operator.

Juk
Quick C++ question Quote
02-13-2008 , 03:24 PM
i'm pretty sure if you have dynamically allocated stuff, the default functionality is to make a copy of the pointer (and not the array), so you're left with two pointers to the same array.
Quick C++ question Quote
02-13-2008 , 04:00 PM
Quote:
Originally Posted by KLJ
i'm pretty sure if you have dynamically allocated stuff, the default functionality is to make a copy of the pointer (and not the array), so you're left with two pointers to the same array.
Yep, that's what I tried to show in my first example (see above). It's not just dynamically allocated memory that causes problems though, but file handles, GUI objects, synchronization objects, etc all end up with just the handle getting copied which nearly always isn't what is wanted.

Juk
Quick C++ question Quote
02-13-2008 , 05:08 PM
Thanks a lot for the help, Juk. One more noob question. I didn't realize how quickly I'd forget these kinds of things after not being in school for awhile.

Again, I'll have a simple class definition:

class TestClass
{ ... }

TestClass someFunction()
{
TestClass testObj; // plus whatever other initialization stuff i want to do
return testObj;
}

If I write code like the above, will that cause any trouble (assuming no dynamically allocated memory in TestClass) when trying to return the entire object back to the caller?

If I changed the function type to TestClass* and returned &testObj, that would cause trouble, correct? Because after the function returned, the memory location at which testObj used to reside could be overwritten by something else at that point.
Quick C++ question Quote
02-13-2008 , 05:14 PM
I guess what's confusing me is the following. I thought when you passed arrays as parameters, they don't get copied for resource reasons. As a result, I thought the same reasoning applied to objects. So now I'm confused exactly when copies are made, and when they are not.
Quick C++ question Quote
02-13-2008 , 05:33 PM
Quote:
Originally Posted by Dazarath
If I write code like the above, will that cause any trouble (assuming no dynamically allocated memory in TestClass) when trying to return the entire object back to the caller?
This should be no problem.


Quote:
If I changed the function type to TestClass* and returned &testObj, that would cause trouble, correct? Because after the function returned, the memory location at which testObj used to reside could be overwritten by something else at that point.
That will be a problem. You are returning a pointer to a variable that got destroyed as soon as the function scope ended. It's pointing to unknown memory. Using this pointer will likely result in a crash.

Quote:
I guess what's confusing me is the following. I thought when you passed arrays as parameters, they don't get copied for resource reasons. As a result, I thought the same reasoning applied to objects. So now I'm confused exactly when copies are made, and when they are not.
It might help if you think of arrays as pointers, which they are unless you are using some sort of class that represents an array.

Copies are made any time you aren't working with pointers and references. Of course, C++ allows you to overload the = operator, so you can do all sorts of fancy things on assignment if you want.
Quick C++ question Quote
02-13-2008 , 06:46 PM
Quote:
If I changed the function type to TestClass* and returned &testObj, that would cause trouble, correct? Because after the function returned, the memory location at which testObj used to reside could be overwritten by something else at that point.
Yep, as PokerAce allready said this will likely cause a crash. It would be fine though if you created the object dynamically inside the function using new and then returned the pointer, but this would be pretty bad coding practice as it gets very easy to lose track of what you've allocated if you don't allocate and deallocate in the same block (or use the OO idea of constructor/destructor).

Another thing to note is if you have a large data-type to return from a function it's usually better to use C++ object references to do it or else you end up making a temporary copy for every return (which gets placed on the stack). See here for an example:

http://www.functionx.com/cpp/example...nreference.htm

Quote:
I guess what's confusing me is the following. I thought when you passed arrays as parameters, they don't get copied for resource reasons. As a result, I thought the same reasoning applied to objects. So now I'm confused exactly when copies are made, and when they are not.
Again as PokerAce already said C and C++ 1D arrays are just a neat way of hiding the base pointer (eg: why you can pass in a char[100] into a char* argument, etc).

Juk
Quick C++ question Quote
02-13-2008 , 07:16 PM
OP this link may be helpful if you run into any other questions...

http://www.cprogramming.com/
Quick C++ question Quote
02-14-2008 , 09:25 PM
Quote:
Originally Posted by jukofyork
Code:
class X
{
  char* S;

  X() { S=new char[100]; }
  ~X() { delete [] S; } 
}

.
.
.

X a;
X b;
a = b;
Will go wrong.

Juk
Out of academic curiosity, will it "go wrong" as in there will be some kind of error/crash? Or will it go wrong because you're creating an unstable situation?

If the former, I don't understand why the 'a = b' wouldn't just copy the value of the S pointer from b to a. You now have char pointers in two different objects pointing to the same location, which is obviously "bad", but won't inherently make your program self-destruct, right?
Quick C++ question Quote
02-14-2008 , 09:45 PM
Having two pointers pointing to the same memory isn't bad. The bad part happens when you go to delete the memory they point to. The destructor of the first object deletes the memory. When the destructor of the second object goes to delete the memory, it no longer points to valid allocated memory. The results of this action is undefined, but usually results in an exception (application crash).
Quick C++ question Quote
02-14-2008 , 09:52 PM
Ok, thanks. I'm pretty good with C but never really learned C++-specific syntax/concepts (I now work in Java).

As for the two pointers referring to the same location being bad, I meant more in the sense that the programmer likely expects that location to be used by only one object so undesirable side effects would likely be caused when the data at that location is modified.
Quick C++ question Quote
02-14-2008 , 09:52 PM
Quote:
Originally Posted by Dazarath
I guess what's confusing me is the following. I thought when you passed arrays as parameters, they don't get copied for resource reasons. As a result, I thought the same reasoning applied to objects. So now I'm confused exactly when copies are made, and when they are not.
just use vectors, imo
Quick C++ question Quote
02-14-2008 , 11:03 PM
Quote:
Originally Posted by goofyballer
As for the two pointers referring to the same location being bad, I meant more in the sense that the programmer likely expects that location to be used by only one object so undesirable side effects would likely be caused when the data at that location is modified.
That too IIRC - but that would just confuse debugging while both copies existed. once the memory is de-allocated by one of them, it *will* be reused for something sometime - then your remaining object tries to write to god-knows-what - and boom

I think. It's been a while.

EDIT:
Quote:
Originally Posted by PokerAce
When the destructor of the second object goes to delete the memory, it no longer points to valid allocated memory. The results of this action is undefined, but usually results in an exception (application crash).
Ooh, do modern OS actually prevent this these days and just throw exceptions? as I say, it's been a while... we used to just be able to trash another running processes memory by accident with wrong pointer stuff IIRC - at least we were careful not to do this for that reason - Was Win98 days FWIW
Quick C++ question Quote
02-15-2008 , 01:28 AM
In Windows it's a special kind of exception. Windows is special.
Quick C++ question Quote
02-15-2008 , 08:24 AM
Quote:
just use vectors, imo
For this example using STL vectors wouldn't work either, as internally they use dynamically allocated memory and the basic compiler generated assignment operator would simply copy the pointer(s) inside the vector class and not the data itself.

Juk
Quick C++ question Quote
02-15-2008 , 08:32 AM
Quote:
Originally Posted by goofyballer
Ok, thanks. I'm pretty good with C but never really learned C++-specific syntax/concepts (I now work in Java).
Even for Java (or any other OO language) it doesn't really fit with the OO idea of encapsulating data to have multiple classes sharing the same data like this.

Very rarely you might actually want to do this, but then you could make it clear by using a single pointer declared as static for all classes to share. At least then if the pointer gets changed it gets changed for all classes.

Juk
Quick C++ question Quote
02-15-2008 , 08:37 AM
Quote:
Originally Posted by _dave_
Ooh, do modern OS actually prevent this these days and just throw exceptions? as I say, it's been a while... we used to just be able to trash another running processes memory by accident with wrong pointer stuff IIRC - at least we were careful not to do this for that reason - Was Win98 days FWIW
It was Windows 3.1 that really suffered bad from this - you could barely keep it running for half a day without something mangling up the OS. God help us if we had to play poker using that POS...

There is some info about why Win95 memory protection wasn't that great here too:

http://everything2.com/index.pl?node_id=668981

but compared to Window 3.1 it was a big improvement.

Juk
Quick C++ question Quote
02-15-2008 , 01:27 PM
Quote:
Originally Posted by jukofyork
For this example using STL vectors wouldn't work either, as internally they use dynamically allocated memory and the basic compiler generated assignment operator would simply copy the pointer(s) inside the vector class and not the data itself.

Juk
are you sure about that? maybe I didn't understand what you meant. i ran this code

Code:
#include <iostream>
#include <vector>
using std::vector; using std::cout; using std::endl;

int main()
{

  vector<int> a,b;
 
  a.push_back(1);
  a.push_back(2);
  a.push_back(3);
  
  b=a;
  a.clear();
  a.push_back(4);

  for (vector<int>::iterator i = a.begin(); i != a.end(); i++)
    cout << *i << " ";
  for (vector<int>::iterator i = b.begin(); i != b.end(); i++)
    cout << *i << " ";
  
  cout << endl;
  return 0;
}
which produced the output "4 1 2 3" as expected. STL containers do have overloaded assignment operators to do this sort of stuff afaik.
Quick C++ question Quote
02-15-2008 , 02:28 PM
Quote:
Originally Posted by jukofyork
For this example using STL vectors wouldn't work either, as internally they use dynamically allocated memory and the basic compiler generated assignment operator would simply copy the pointer(s) inside the vector class and not the data itself.

Juk
This is incorrect. std::vector:perator= does what you think it should do.
Quick C++ question Quote
02-15-2008 , 02:46 PM
OP, the answer to your original question:

Quote:
In C++, what does the assignment operator '=' do for classes, assuming that I haven't overloaded it.
Is that the compiler will do member-wise copy construction on each member in your class. So for example if you have:

#include <cstdlib>
#include <string>


class foo
{
public:
int a, b, c;
std::string s;
};

int main()
{
foo right;
right.a = 1;
right.b = 2;
right.c = 3;
right.s = "hello foo";

foo left = right;

return 0;
}

...the statement 'foo left = right' resolves to the semantic equivilent of this:

left.a = right.a;
left.b = right.b;
left.c = right.c;
left.s = right.s;


Note that 'left.s = right.s;' works because std::basic_string has an overload which does what you would expect it to do.
Quick C++ question Quote
02-15-2008 , 02:53 PM
Quote:
Originally Posted by Grunch
This is incorrect. std::vector:perator= does what you think it should do.
But the OP was asking about what happens if you assign one class to another containing other stuff (ie: constraining an STL vector in this case).

If you use a STL vector inside another class which doesn't have an assignment operator defined, then the compiler generated default assignment operator will not invoke the assignment operator of the SDL vector contained within it.

Juk

EDIT: See post below.

Last edited by jukofyork; 02-15-2008 at 03:05 PM.
Quick C++ question Quote
02-15-2008 , 03:04 PM
Quote:
#include <cstdlib>
#include <string>


class foo
{
public:
int a, b, c;
std::string s;
};

int main()
{
foo right;
right.a = 1;
right.b = 2;
right.c = 3;
right.s = "hello foo";

foo left = right;

return 0;
}

...the statement 'foo left = right' resolves to the semantic equivilent of this:

left.a = right.a;
left.b = right.b;
left.c = right.c;
left.s = right.s;
I was always under the impression that 'foo left = right' resolves to 'memcpy((void*)&left,(void*)&right,sizeof(foo)', but after reading a bit more I think I'm wrong here:

http://www.codeproject.com/KB/recipe...yingRules.aspx

Juk

EDIT: I am definitely wrong here. It seems that C++ does a "shallow memberwise copy" (see here) and I was assuming it only did a "bitwise copy". So the assignment operator will get called for each member, but the "shallow" part means that pointer assignment will only make a copy of the pointer as opposed to "deep" which would make a copy of the memory that the pointer pointed too.

Last edited by jukofyork; 02-15-2008 at 03:16 PM.
Quick C++ question Quote
02-15-2008 , 03:26 PM
Right, I misunderstood.

Quote:
Originally Posted by jukofyork
But the OP was asking about what happens if you assign one class to another containing other stuff (ie: constraining an STL vector in this case).

If you use a STL vector inside another class which doesn't have an assignment operator defined, then the compiler generated default assignment operator will not invoke the assignment operator of the SDL vector contained within it.
Not to pick nits, but this is a pretty important distinction that confuses many people. It doesn't depend on having an operator= in your containing class; it depends on having a copy constructor. Take a look at the following code:

Code:
#include <cstdlib>
#include <vector>
#include <iostream>

class foo
{
public:
	std::vector<int> nums;
	foo& operator=(const foo & rhs) 
	{
		nums.clear();
		for( std::vector<int>::const_reverse_iterator it = rhs.nums.rbegin(); rhs.nums.rend() != it; ++it )
			nums.push_back(*it);
		return * this;
	}

	foo() {};
	foo(const foo& rhs) { operator=(rhs); }
};

class bar
{
public:
	foo fighter;
};


int main()
{
	bar right;
	right.fighter.nums.push_back(1);
	right.fighter.nums.push_back(2);
	right.fighter.nums.push_back(3);

	bar left = right;

	for( std::vector<int>::iterator it = left.fighter.nums.begin(); left.fighter.nums.end() != it; ++it )
		std::cout << *it << " ";

	return 0;
}
The output as shown is "3 2 1". If you comment-out only the constructors in 'foo' but leave the operator= overload in:

Code:
class foo
{
public:
	std::vector<int> nums;
	foo& operator=(const foo & rhs) 
	{
		nums.clear();
		for( std::vector<int>::const_reverse_iterator it = rhs.nums.rbegin(); rhs.nums.rend() != it; ++it )
			nums.push_back(*it);
		return * this;
	}

//	foo() {};
//	foo(const foo& rhs) { operator=(rhs); }
};
...the output will be "1 2 3".
Quick C++ question Quote
Quick C++ question
150% up to $2,000 Welcome Bonus on CoinPoker
Join the action now
Daily Rewards • Splash Pots • CoinRaces
Quick C++ question

      
m