Thread: How vector manages space

  1. #1
    Registered User
    Join Date
    Oct 2007
    Posts
    4

    How vector manages space

    Hi All,

    Please look at the code below.

    In set() fucntion, I am building a vector test_values. In this, I am pushing local block values. Which goes out of scope when function exits.

    When control comes to onEvent(), I am able to extract exact values that I have pushed in set().

    How is this working?

    All local that I have pushed are out of scope, then how test_values vector is containing the right values.


    Code:
    /*******************************************************************************************/
    class abc {
    public:
    	set();
    	onEvent();	
    private:
    	struct test {
    		int a;
    		char b;
    	};
    
    	std::vector<struct test> test_values;
    };
    
    void abc::set()
    {
    	struct test st1;
    	st1.a = 1;
    	st1.b = 0;
    	
    	test_values.push_back(st1);	
    
    	st1.a = 2;
    	st1.b = 1;
    	test_values.push_back(st1);	
    
    	st1.a = 3;
    	st1.b = 2;
    	test_values.push_back(st1);	
    	
    }
    
    void abc::onEvent()
    {
    	test_values[0].a;
    	test_values[0].b;
    	test_values[1].a;
    	test_values[1].b;
    	test_values[2].a;
    	test_values[2].b;
    
    }
    /***************************************************************
    ****************************/
    thanks in advance.
    Jack

  2. #2
    The larch
    Join Date
    May 2006
    Posts
    3,573
    This works because the vector makes a copy of what you put into it.

    If it didn't do that, what use would the container have if you needed to keep the objects you have created around for the vector to work?!
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  3. #3
    Registered User
    Join Date
    Oct 2007
    Posts
    4
    Thanks anon.

    If vector makes a copy to what it points to, then it must be calling its contructor. Then I must be able to walk through its contructor (by putting a break point in the contructor of the vector).

    When I am pushing the pointer, that time it returns me exactly the same object that I have pushed. But in the above case, its not the same, as

    struct test st1;

    is local.

    Does vector make a copy of it that time also.

    This might sound stupid, But I really want to understand it.

  4. #4
    The larch
    Join Date
    May 2006
    Posts
    3,573
    When you insert something into a vector, it makes a copy of it, using the copy constructor of the object you are inserting. In your code, the compiler generates a suitable copy constructor for struct test automatically.

    For example, the following code fails to compile, because the user-defined copy constructor is private (making the object non-copiable), and hence inaccessible for the vector.

    Code:
    #include <vector>
    
    class A
    {
        public:
            A() {}
        private:
            A(const A&); //private copy constructor
    };
    
    int main()
    {
        std::vector<A> vec;
        A a; //OK
        vec.push_back(a); //error, copy constructor is inaccessible
    }
    I don't understand your point about stepping through the constructor of the vector. In your code the vector is a class member and will be constructed (correctly - as an empty vector) by the compiler-generated constructor of class abc. If the (compiler-generated) copy constructor of struct test is OK (in your code it is) there shouldn't be any problems pushing the local test instances (their copies) into the vector.

    Are you having some problems or do you just want to be sure?
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  5. #5
    Registered User
    Join Date
    Oct 2007
    Posts
    4
    Thanks for the code snippet. This cleared my confusion.

    By stepping out, I mean, to see where copy is made by the vector. Here is were object is made, and this leads to invoke copy contructor of the class.


    template<class _T1, class _T2> inline
    void _Construct(_T1 _FARQ *_P, const _T2& _V)
    {new ((void _FARQ *)_P) _T1(_V); }

    No, I am not having any problem. I am trying to understand vectors.

    I have modified code little bit, I want to see whether my understanding is right or wrong.
    Code:
    /********************************************/
    #include <vector>
    
    class A
    {
       public:
           A() {}
       //private:
           A(const A&) {
    	   }; //private copy constructor
    
    };
    
    void func();
    
    std::vector<A*> vec1;
    std::vector<A> vec2;
    
    void func()
    {
    	A* test1 = vec1[0];
    	A test2 = vec2[0];
    }
    
    int main()
    {
    	A *a = new A;
    	vec1.push_back(a);
    
    	A b;
    	vec2.push_back(b);
    	
    	func();
    
    	return 0;
    }
    
    /********************************************/
    Case 1,
    A *a = new A;
    vec1.push_back(a);

    no copy constrcutor is invoked.

    Case 2,
    A b;
    vec2.push_back(b);


    copy constrcutor is invoked.

    Case 3,
    A* test1 = vec1[0];

    no copy constrcutor gets invoked.

    Case 4,
    A test2 = vec2[0];


    copy constrcutoris invoked.

    In case 4, Why vector is not retuning the same copy that it has created earlier. Do I understand, it keeps the information and builds again object, which leads to call copy constrcutor.

  6. #6
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    You won't understand vectors by reading the source code of an STL implementation. It's usually unreadable, due to various minor optimizations or whatever.

    You might learn a lot by implementing one, though.

    Anyway, regarding case 4, vector is returning the copy you created earlier. It is you who makes the copy. Try
    A &test2 = vec2[0];
    and there should be no copy constructor call.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  7. #7
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Firstly the difference between the two vectors:
    Code:
    std::vector<A*> vec1;
    std::vector<A> vec2;
    The first is a vector of pointers. The vector will store a copy of the pointer to the object, and copying a pointer doesn't involve copying the object. Both the pointer inside the vector and the original pointer outside point to the same object. The original pointer may go out of scope, but if the vector lives longer, the object will still be accessible through the pointer stored in the vector.

    If you use new to allocate objects, you are also responsible for delete'ing each instance, to avoid memory leaks.

    It would be dangerous to do something like this:
    Code:
    std::vector<A*> ptr_vec;
    A a; //local instance
    ptr_vec.push_back(&a); //store address
    In this case the vector contains the address of a local object. If the local object goes out of scope, the pointer stored in the vector becomes invalid. (This is the scenario that you originally seemed to worry about.)

    2.
    Code:
    A test2 = vec2[0];
    This involves copying, because you have declared another instance of type A (test2) which is distinct from what vec2[0] contains. The object needs to be copied over. Modifying test2 will have no effect on the object stored in the vector.

    You can avoid the copy and declare a reference to an A instance (because operator[] actually returns a reference, not a copy):
    Code:
    A& test2 = vec2[0];
    Now, test2 is referencing the same object that is stored in the vector. Anything you do to test2 will change the A object at vec2[0]. If that is what you want, fine.

    Using a reference like that might be dangerous because for certain operations - e.g push_back, erase etc - the vector might move the objects it is storing around in memory or destruct them (for each container type find out which methods would invalidate iterators).

    It is not entirely uncommon to use the returned reference temporarily (without declaring a separate reference). Supposing class A had a public int member value, you might do:
    Code:
    vec2[0].value = 42;
    Last edited by anon; 10-01-2007 at 09:40 AM.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  8. #8
    Registered User
    Join Date
    Oct 2007
    Posts
    4
    Thanks anon , Thanks CornedBee,

    I have got more clearity now.

    I am trying now the dangerous part,


    std::vector<A*> ptr_vec;
    A a; //local instance
    ptr_vec.push_back(&a); //store address

    I am accessing the object ptr_vec[0] from another function, and its returning me the same &a which i pushed earlier. I know this is not the right behaviour.
    But why its happening, how this can be prevented.

    Thanks in advance,

  9. #9
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    The code is just doing what you asked for. There is no real good way to avoid this - you may well WANT to do this under certain circumstances (e.g. you create a local vector within a function A, call some other functions (B, C, D, ...) and then destroy the vector again before you leave the function A) so completely forbidding it is a bad idea. It is just the same as "if there's a speed limit, doesn't mean that cars can't break this speed limit (currently)" - you just aren't supposed to do this.

    Whether this actually fails in a particular case or not depends on what you do in your code and the next function - so it's not absolutely certain to ALWAYS fail - it may fail one case, and in another case work fine. This is of course the scary part!

    It should of course return the same address as you pushed in - the point is rather that this address is now either unused or used for something else - and if it's unused, it would possibly be used if you change the code, add more local variables or call a different function someplace between your insertion in the vector and the use of it later on.

    Note that there are other "breakable" ways to use vectors or other classes that store pointers to objects - if you use new to create a new object, inster this in a container class and then delete the object, you'll still have the objects address within the vector, and as long as the object's memory address hasn't been used for something else, it will still look "fine" in there.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Out of space when compiling kernel
    By NuNn in forum Linux Programming
    Replies: 3
    Last Post: 04-01-2009, 02:43 PM
  2. disk space mysteriously gone
    By evader in forum C++ Programming
    Replies: 4
    Last Post: 01-21-2004, 01:30 PM
  3. Replies: 12
    Last Post: 05-17-2003, 05:58 AM
  4. someone who is good at finding and fixing bugs?
    By elfjuice in forum C++ Programming
    Replies: 8
    Last Post: 06-07-2002, 03:59 PM