• 10
• 9
• 13
• 10
• 18

Local objects in c++

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

Recommended Posts

Hi, if i have some function like this:
void my_add_vertex()
{
g_vertexArray.push_back(CVertex(1.0, 1.0, 1.0));
}


then i create an instance of CVertex, which is only valid inside the my_add_vertex runtime, and it is passed as a reference to push_back. Is this dangerous? the constructor of CVertex only initializes x, y and z (and other data members). i see this practice in many tutorials, and from my state of knowledge, i would say that it is unsafe to pass a reference to a local variable, though i get no compiler warning. would be nice if you could shed some light on this. thanks Gamma_strahler

Share on other sites
push_back takes arguments by value, not reference.

More generally, a temporary value is guaranteed to stay alive until the end of the operation which uses it (typically a function call), and so it may be passed by constant reference.

Share on other sites
Quote:
 Original post by ToohrVykpush_back takes arguments by value, not reference.
Actually, push_back() takes arguments by const reference.

push_back() makes a copy of the variable you pass it, and keeps that in the vector (or list, or whatever). So it's safe to do.

Share on other sites
You're right. Don't know what got into me, possibly my lack of sleep [smile] I guess I compressed "copies a constant reference" into "by value" without noticing.

Share on other sites
Thanks for your answers, but there is one problem left which i don´t really understand.

I have encountered that this only works as long as i don´t allocate dynamic memory in an object.

For example, the following code crashes (which uses the free store for a data member):

struct vector3{    float _x, _y, _z;    char *_p;    vector3(float x, float y, float z) : _x(x), _y(y), _z(z)     {         _p = new char [1024];    }	    ~vector3()     {        if (_p)	    delete [] _p;	_p = 0;    }};using namespace std;vector<vector3> g_vertexArray;void do_another_thing(){    g_vertexArray.push_back(vector3(0, 1, 2));}void main(){    do_another_thing();    for (vector<vector3>::iterator it = g_vertexArray.begin();	  it != g_vertexArray.end(); ++it)    {	cout << it->_x << endl;  // CRASH!!!!    }}

Share on other sites
ups... sorry for the double-post

Share on other sites
Your class requires a non-default copy constructor and assigment operator. Otherwise, the copy will use the same pointer as the original, and the pointer will be deleted when the original is destructed, placing the copy in an invalid state.

Share on other sites
Yes that would crash as you are not following the rules for the STL containers. Basically the object you pass in is going to be copied many times when you adjust the container, so a deep copy is required for your structure. The language supplies a default copy constructor and assignment operator and this is what is being used, but as a member you have heap memory which is release in the destructor. The default copy constructor is doing a one for one copy; copying the pointer which each object will try and delete. Then you will get a segmentation fault as you are double deleting.

Share on other sites
Quote:
 Original post by gamma_strahlerThanks for your answers, but there is one problem left which i don´t really understand.I have encountered that this only works as long as i don´t allocate dynamic memory in an object.For example, the following code crashes (which uses the free store for a data member):*** Source Snippet Removed ***

Your struct does not have a proper implementation of a copy constructor, so is not valid for use in a std::vector. You could waste time writing one for it, or you could make it use std::string (or std::vector for non-text) [smile]

struct vector3{    float _x, _y, _z;    std::string _p;    // I dont know where 1024 came from, but Ill keep it here    // although you can omit it, std::string will grow for you    vector3(float x, float y, float z) : _x(x), _y(y), _z(z), _p(1024)     {    }    // no destructor or copy constructor needed!    // the compilers default generated ones will suffice.};

The rule is, if a class requires a copy constructor, destructor or overloaded operator=(), then it probably requires all three (or for them to be explicitly declared private and unimplemented so the compiler will catch any mistakes).

One little thing, dont use "if(ptr)delete ptr;". Calling delete or delete [] on a NULL pointer is ok, delete does the check for you.

Share on other sites
Juse to point out passing a tempoary to a function taking a const reference can be dangerous in some cases.

Example:
const vector3& identity(const vector3& value){ return value; }int main(){    const vector3& vec = identity(vector(0, 0, 0));    // vec now refers to the tempoary which may have already been destroyed}

Although the example is extremly contrived I have seen the problem come up with operator chaining and tempoary std::stringstream's.