Pushing Back Class Objects to a Vector

Here, in the code. While I'm pushing back that obj2 to vector, is it creating another class object? Because my settings are not affecting this vector element. How can I prevent this? Is there a way to make it the same as my object and can I able to control it without explicitly calling it?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>
#include <vector>

using namespace std;

class Test 
{
    int a;
    int b;
public:
    Test();
    Test(int, int);

    void setA (int);
    int getA ();
};

Test::Test ()
    : a{}, b{}
{

}

Test::Test (int aV, int bV)
    : a{aV}, b{bV}
{

}

void Test::setA (int val)
{
    a = val;
}

int Test::getA ()
{
    return a;
}

int main ()
{
    vector <Test> vec;

    Test obj1 {1,2};
    vec.push_back(obj1);

    Test obj2;
    vec.push_back(obj2);

    obj2.setA(1);

    cout << "Obj 1s a value: " << obj1.getA() << endl;
    cout << "Obj 2s a value: "  << obj2.getA () << endl;
    cout << "Maybe Obj 2s a value?: " << vec.at(1).getA() << endl;


}
Last edited on
std::vector stores copies of the objects that you insert. If you don't want this you could create a vector of pointers and insert pointers to the objects instead. Note that this will not extent the lifetime of the objects automagically so be careful.
Last edited on
Peter87. Thank you, man. You saved 250 lines of code. But you're saying using pointers is a no-no. Right?
you're saying using pointers is a no-no. Right?

No, I don't. It depends.

If you know that all objects will stay alive for at least as long as the vector then you can use pointers.

In some situations it might be better to use "smart pointers" (e.g. std::unique_ptr).
Last edited on
I got you. I'm learning these classes still. And deep copy constructor's purpose is to close the what did you say. I think that smart pointers are easier.
Also, there is emplace_back which constructs the object in the container directly, no copies :+)

Enjoy
The references to the objects already in the vector would be invalidated if emplace_back triggers a reallocation. We could use an early reserve to prevent this. Or if fast random access is not a requirement, this is a canonical use case for std::list

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>
#include <vector>

struct test
{
    test( int aa = 0, int bb = 0 ) noexcept : a(aa), b(bb) {}

    void print() const { std::cout << "test{a==" << a << ",b==" << b << "}\n" ; }

    int get_a() const noexcept { return a ; }
    int get_b() const noexcept { return b ; }

    void set_a( int v ) noexcept { a = v ; }
    void set_b( int v ) noexcept { b = v ; }

    private:
        int a ;
        int b ;
};

int main()
{
    std::vector<test> all_tests ; // empty vector
    all_tests.reserve(10) ; // reserve space for ten objects (prevent reallocation)

    // add two objects to the vector
    all_tests.emplace_back(1,2) ; // construct test(1,2) in-place in the vector
    test& obj1 = all_tests.back() ; // get a reference to the object that was added
    all_tests.emplace_back() ; // default construct a test in-place in the vector
                               // (the capacity is adequate; so references to objects in the vector are not invalidated)
    test& obj2 = all_tests.back() ; // get a reference to the second object that was added

    // modify the objects in the vector
    obj1.set_a(123) ;
    obj1.set_b(4567) ;
    obj2.set_a(888) ;
    obj2.set_b(9999) ;

    // print the objects in the vector
    for( const test& t : all_tests ) t.print() ;
}

http://coliru.stacked-crooked.com/a/229ef9068339f0f4

Or:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int main()
{
    std::list<test> all_tests ; // empty list

    // add two objects to the list
    all_tests.emplace_back(1,2) ; // construct test(1,2) in-place in the list
    test& obj1 = all_tests.back() ; // get a reference to the object that was added
    all_tests.emplace_back() ; // default construct a test in-place in the list
    test& obj2 = all_tests.back() ; // get a reference to the second object that was added

    // modify the objects in the list
    obj1.set_a(123) ;
    obj1.set_b(4567) ;
    obj2.set_a(888) ;
    obj2.set_b(9999) ;

    // print the objects in the list
    for( const test& t : all_tests ) t.print() ;
}

http://coliru.stacked-crooked.com/a/846814a949f0fce1
emplace_back returns a reference to the newly inserted element since C++17 so instead of
1
2
all_tests.emplace_back(1, 2);
test& obj1 = all_tests.back();
you can write
 
test& obj1 = all_tests.emplace_back(1, 2);
A question is, do you really need to access an object both via obj2 and via vec.at(1)?


With std::unique_ptr, there can be only one! A unique_ptr is "unique", because it is the only pointer that points to object with intent to manage the object's lifetime.
> With std::unique_ptr, there can be only one!

Ensuring that there is only one smart pointer that owns an object is the responsibility of the programmer.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <memory>

struct A
{
    A() { std::cout << "construct object at " << this << '\n' ; }
    ~A() { std::cout << "destroy object at " << this << '\n' ; }
};

int main()
{
    A* p = new A ;
    std::unique_ptr<A> pa1(p) ; // hand over ownership of the object to pa1
    std::unique_ptr<A> pa2(p) ; // hand over ownership of the object to pa2
    // destructors of pa2, pa1 engender undefined behaviour
}

http://coliru.stacked-crooked.com/a/073276e8b988ec17
std::vector owns its elements.

A std::vector of std::unique_ptr essentially accomplishes the same thing but has the advantage that you can freely remove and add new objects without having to worry about invalidating pointers/references to the other objects, and if you want you can even transfer the ownership of the objects (such as to another vector).

Note that just because you use std::unique_ptr doesn't mean you can't have other non-owning pointers/references to the objects. This is very common when passing objects to functions. You normally don't pass a std::unique_ptr to a function unless it deals with ownership, instead you pass the object itself by reference as normal.
Last edited on
You normally don't pass a std::unique_ptr to a function unless it deals with ownership, instead you pass the object itself by reference as normal.

A decent explanation (for me, at least) about passing all three types of smart pointers into and out of functions:
https://www.internalpointers.com/post/move-smart-pointers-and-out-functions-modern-c

A beginner's look at smart pointers in modern C++ to point out the various types of smart pointers and why there are three types instead of one:
https://www.internalpointers.com/post/beginner-s-look-smart-pointers-modern-c

There are some other useful articles on C++ here:
https://www.internalpointers.com/category/programming
Topic archived. No new replies allowed.