PDA

View Full Version : Weird thing while trying to avoid pointers in C++



ct
14th February 2011, 07:50
I had this weird thing while I was trying to avoid pointers and just create objects on the stack.



#include <iostream>
#include <string>
#include <cstring>
#include <vector>
#include <cstdio>
using namespace std;

class Node {
public:
string move;
int state[10];
Node(const Node &p) {
move = "";
memcpy(state,p.state,sizeof(int)*10);
}
Node(){
move = "";
for(int i = 0;i<10;i++){
state[i] = i;
}
}
void AddNode(Node p){
this->childNode.push_back(p);
}
Node GetChild(int i) {
return childNode[i];
}
int GetCount() {
return this->childNode.size();
}
protected:
vector<Node> childNode;
};

class Move {
public:
Move() {

}
void run() {
Node n;
n.move = "A100";
operate(n);
}

void operate(Node &n) {

Node c(n);
c.move = "B100";
n.AddNode(c);
cout << "Output : " << endl;
Node t = n.GetChild(n.GetCount() - 1);
//Node t = n.childNode[0];
for(int i = 0;i<10;i++)
cout << t.state[i];


cout << endl << t.move; // doesn't display B100 ????

}

};

int main(int argc,char** argv) {

Move m;
m.run();
return 0;
}


Here is a sample of something that I'm trying to do. My question is why isn't B100 move displayed ? Do I need an assignment operator in the Node class ? I believed push_back takes references and that the node with move value B100 should be stored in the vector. Correct state array is stored but the move string is not, any suggestions ?

high_flyer
14th February 2011, 08:11
... where to begin...

believed push_back takes references and that the node with move value B100 should be stored in the vector.
Programming is not a religion.
You don't believe stuff, you read the docs!
Since your definition of your vector was not with reference, it takes copies, not references.
I am not sure even why this code compiles, since you are trying to assign c to t but you didn't define an '=' operator for your Node class.


Node t = n.GetChild(n.GetCount() - 1); //I don't know why this compiles, it should not

maybe a default assignment operator is called, but it knows nothing about your Node members, so it can't possibly copy inner members of your Node members such as 'move'.

ct
14th February 2011, 08:21
Well it does take reference.


void push_back ( const T& x );

However, even if it takes copy, shouldn't there be a value of move in the vector ?

I added the assignment operator


Node& operator=(const Node &r) {

if(&r != this) {
memcpy(this->state,r.state,sizeof(int)*10);
this->move = r.move;

}

return *this;
}


But still There is no output.

stampede
14th February 2011, 09:21
Take a look at your copy constructor:

Node(const Node &p) {
move = ""; //!< change this to p.move
memcpy(state,p.state,sizeof(int)*10);
}
When you take out an object from vector, it's copy is made and previously assigned string is cleared in your copy-constructor.

------------------
ok, maybe i was not clear enough, i mean this line:

Node t = n.GetChild(n.GetCount() - 1);
this is copy - construction, its not the same as:

Node t;
t = n.GetChild(n.GetCount() - 1);
Assignment operator is not called anywhere in your code ( add cout's to see it yourself ).

high_flyer
14th February 2011, 09:44
Well it does take reference.
That is true, however think about it:
If it really only took a reference, and left it as a reference, all the original objects you would assign to it would need to stay alive, which is not the case.
So it takes a reference, but internally it creates a copy.

Zlatomir
14th February 2011, 10:13
Unless you define the vector as QVector<MyObject&> - then it indeed will take references.
I'm pretty sure you can't do that, since references in C++ have their "oddies" (like the reference is for all it's life bound to an object and it should be set at declaration)

So the remaining solution is QVector<MyObject*>

high_flyer
14th February 2011, 10:19
You are correct Zlatomir.
I have never tried it before actually, because it never made any practical sense.
I just assumed it is possible.
Now I tried it, and indeed, the compiler complains.
Thanks for the heads up!

wysota
14th February 2011, 17:55
I am not sure even why this code compiles, since you are trying to assign c to t but you didn't define an '=' operator for your Node class.


Node t = n.GetChild(n.GetCount() - 1); //I don't know why this compiles, it should not

This is equivalent to:

Node t(n.GetChild(n.GetCount()-1));
The copy constructor kicks in here. Besides if you don't declare your own default constructor, copy constructor or assignment operator, the compiler will provide them for you.



Well it does take reference.


void push_back ( const T& x );
No, it takes a const reference. That's two totally different things.

ct
14th February 2011, 18:53
Thanks, I got it. The copy constructor was being called all the time. I got the difference now.

ct
15th February 2011, 06:27
One more thing on the topic though. Is it a good practice to avoid using pointers and use the stack space instead of heap ? That way there would be no memory leaks.

SixDegrees
15th February 2011, 07:48
No; that will quickly lead to convoluted code in all but the simplest applications. Pointers are fundamental to C/C++; there is no reason to avoid them.

If you're really worried about memory leaks, have a look at the STL auto_ptr class. Or run your code through a tool like valgrind to check for memory leaks, which is something you really ought to be doing anyway.

high_flyer
15th February 2011, 09:01
In addition to what has been said, the stack size is usually quite limitted, so any realy world application might soon run out of memory if all you use is the stack.

Zlatomir
15th February 2011, 16:22
Just a little addition to what has been said already: don't use auto_ptr it has some usage restriction (like you can't have an container of auto_ptr) and if i remember correctly it is on removal list of the new standard, so you will have to re-write code when you will upgrade to a C++0x compiler.

Instead you can use boost shared_ptr (it should be included in tr1:: namespace it will be in std:: in C++0x) or Qt has QSharedPointer (http://doc.qt.nokia.com/4.7-snapshot/qsharedpointer.html)

But anyway you need to understand pointers and memory management, even if Qt simplifies things (see parent-child relationship) you still need to know what is deleted by parent and what you should delete yourself.

ct
16th February 2011, 06:43
In addition to what has been said, the stack size is usually quite limitted, so any realy world application might soon run out of memory if all you use is the stack.


Is there a way to find out how much memory is the stack limited to. I'm just writing a prototype and yes memory is a issue. But I would only need around 200-300 mb max. I'm trying to import large text files.

SixDegrees
16th February 2011, 07:56
On Linux, you can say 'ulimit -a'; one of the numbers reported is stack size. On my machine, it is currently set at ~8MB, which is fairly typical.

ct
16th February 2011, 16:18
Which space does STL containers like vector or hash_map use ?
For example:



int main(int argc,char **argv){
vector<string> v;
string s = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaa";
//sizeof(s) = 8
for(unsigned long i = 0;i< 18446744073709551615; i++)
v.push_back(s);
return 0;
}


Isn't the vector being created on the stack ? Why doesn't this program crash even when the size goes way past stack limit (~8 MB) .

high_flyer
16th February 2011, 16:45
Isn't the vector being created on the stack ?
The vector object yes, the elements no.
Think about it: since the elements are being dynamically added, how could they be added on the stack?
That would mean that the vector has a predefined size.

ct
17th February 2011, 00:55
But we don't need to deallocate the memory of vector or other STL containers ? Does it mean that as soon as the object created on the stack runs out of scope, it's memory on heap is deallocated automatically ?
If it does clean up, then I should be ok. I have designed the class such that instead of dynamically allocating objects, i'm inserting it in the vector so that when it runs out of scope, memory will be freed.

stampede
17th February 2011, 08:45
But we don't need to deallocate the memory of vector or other STL containers ?
If you use the container like this:

std::vector<MyClass> v;
v.push_back( MyClass() );
//...
you don't need to de-allocate anything, vector will remove all of it's elements when it runs out of scope. But if you store pointers:

std::vector<MyClass*> v;
v.push_back( new MyClass() );
//...
then you need to remove the objects yourself. When vector runs out of scope it still removes all of it's elements, but this time no ~MyClass destructor is called - since it's just a pointer that is removed - and if you don't do proper cleanup yourself, you'll have a memory leak.


Does it mean that as soon as the object created on the stack runs out of scope, it's memory on heap is deallocated automatically ?

class A{
public:
A(){
b = new B();
}
~A(){
}
B * b;
};

//...
{
A a;
} // a (created on stack) goes out of scope here...


... but a.b (object created on heap) will not be removed automatically, you need to call "delete b" yourself.