I'm working on a C++ project and I wonder if it's possible to store the same object in two different vector. I know how to deal with it in C with pointer, so you reference the same object to both table, but I'm little bit confused in C++.
If I create an object and I store it in vector a and in vector b. Do C++ copy the object or it's the same on both vector and if I modify one, the other is modified too ? In the second case, does it take more place to store it twice (for accessibility issues) or it's not a good way to deal with it ?
Thanks.
Cppreference is a great place to check exactly this type of questions. Let me quote the relevant parts of the link:
void push_back( const T& value );
void push_back( T&& value );
Appends the given element value to the end of the container.
1) The new element is initialized as a copy of value.
2) value is moved into the new element.
So yes, storing the same element twice in two vectors will cause it to get copied twice. You should use std::vector<T*> if you don't want to waste memory. And as always, you should also consider smart pointers (std::shared_ptr / std::weak_ptr) instead of naked pointers.
It's similar to C, really.
If what you have is a vector<object>, then you'll be working with different objects.
On the other hand, a vector<object*> ensures that you'll only be storing pointers to your objects and then having multiple vectors containg the same object or objects is not an issue.
You might also consider using std::shared_ptr and std::weak_ptr to simplify memory management when working with pointers in C++.
When you insert an object into a std::vector a copy of it is made:
Foo a;
std::vector<Foo> vec1;
std::vector<Foo> vec2;
vec1.push_back(a); //copy made
vec2.push_back(b); //copy made
If you do not want a copy, you can either use pointers or std::reference_wrapper (you can't use references as they don't fulfil constraints on container value types):
Foo a;
std::vector<Foo*> vec1;
std::vector<std::reference_wrapper<Foo>> vec2;
vec1.push_back(&a); //no copy
vec2.push_back(std::ref(b)); //no copy
Of course, now no need to ensure that the lifetime of a is no shorter than that of the vectors, otherwise you're on the fast-track to undefined behaviour.
You could also use std::shared_ptr which will ensure that your object is destructed when there are no more references to it:
std::shared_ptr<Foo> a = std::make_shared<Foo>();
std::vector<std::shared_ptr<Foo>> vec1;
std::vector<std::shared_ptr<Foo>> vec2;
vec1.push_back(a); //reference count incremented
vec2.push_back(a); //reference count incremented
I made a simple example for you:
class SomeObject { public: int a; };
int main()
{
SomeObject some_object;
some_object.a = 1;
//Copies are made
std::vector<SomeObject> foo;
foo.push_back(some_object);
std::vector<SomeObject> bar;
bar.push_back(some_object);
foo.at(0).a = 2;
bar.at(0).a = 3;
std::cout << foo.at(0).a << ' ' << bar.at(0).a;
//Refers to the same object
std::vector<SomeObject*> baz;
baz.push_back(&some_object);
std::vector<SomeObject*> foobar;
foobar.push_back(&some_object);
baz.at(0)->a = 4;
foobar.at(0)->a = 5;
std::cout << ' ' << baz.at(0)->a << ' ' << foobar.at(0)->a;
return 0;
}
Outputs:
2 3 5 5
Related
I have an vector, filled with objects:
std::vector<MyClass> vec;
vec.push_back(MyClass("Hi", 10)); //example, could be any class
Later, when it is filled, I want to access it:
for(unsigned int i = 0; i < vec.size(); i++)
{
MyClass *c = & vec.at(i); // <--- HERE
if(c) // <--- AND HERE
{
c->memberOfMyClass = x;
}
}
Is using c more dangerous than using vec.at(i) directly?
Do I need the protection with if(c)? Can c be nullptr? I guess no, because the vector does take object, not pointer to objects.
Is using c more dangerous than using vec.at(i) directly?
Not in the example. It is unnecessarily complex however.
Can c be nullptr?
Not in the example.
Do I need the protection with if(c)?
No; see above.
Is using a pointer to an elements in an vector dangerous?
Using pointer - or any other form of indirection - in general can be "dangerous" in the sense that the lifetimes of the pointer and the pointed object are separate. Therefore you must be aware of what the lifetime of the pointed object is because if it is shorter than the pointer, then pointer will be left "dangling". Assuming the lifetime wrongly can lead to undefined behaviour.
An example of a broken program:
std::vector<MyClass> vec{
{"Hi", 10},
};
MyClass *c = &vec.at(0); // OK
vec.emplace_back("Hi again", 42); // c may be invalid now
c->memberOfMyClass = x; // potential undefined behaviour
A pointer that you acquire with & can't be null, so there is no danger and no point in checking.
(You might be thinking about how a pointer to an element may become invalid if you add or remove elements to the vector, but it will never become null and you can't detect this.)
It's common to use a reference in this situation:
MyClass& c = vec.at(i);
c.member = x;
but with your specific loop, consider using a range loop instead:
for (auto& c : vec)
{
c.member = x;
}
First of all its better to use reference instead of pointer.
You don't need to check pointer if you are sure you have at least i items in vector.
You can use reference/pointer as long as iterators is not invalidated. Read section "Iterator invalidation" here: https://en.cppreference.com/w/cpp/container/vector
it's a better way to access, if you have to do multiple access to the same element of the vector.
I'm new to c++. I came across some code and got confused
vector<int> vec{3,1,4,1,5};
vector<int> &vecRef = vec;
auto vecCopy = vecRef; // makes copy of vec
auto &vecRef2 = vecRef; // reference
I read about the usage of reference types in c++ and I understand why it's useful for immutable types. But for mutable types like vectors, what's the difference between vector vecCopy = vec and vector& vecRef = rec? Aren't they both alias to vec?
But for mutable types like vectors, what's the difference between
vector vecCopy = vec and vector& vecRef = rec? Aren't they both alias
to vec?
No. One is a copy of the entire vector. The other is a reference to the same.
Your example code is contrived. I can't think of any reasons why you would do this:
vector<int> vec{3,1,4,1,5};
vector<int> &vecRef = vec;
You pass variables by reference all the time. But I can't imagine a reason why I'd make a reference to a local variable like this, other than to illustrate an example of references as opposed to copies.
So: vecCopy is a whole DIFFERENT vector with its own contents. At the end of your code, it's identical in contents to vec, but after that, you can add to one or the other and they begin to diverge. vecRef is a reference to the exact same data. If you think of them as (under the hood) pointers, they point to the same object.
Difference between references and values.
One of the features of C++ is that it distinguishes between references and values. A lot of other languages don't do this. Let's say you have a vector:
std::vector<int> v1 = {1, 2, 3};
Creating a deep copy of this vector is really simple:
auto copy_of_v1 = v1;
We can prove it by changing copy_of_v1:
std::cout << (v1 == copy_of_v1) << '\n'; // Prints 1, for true
copy_of_v1[1] = 20; // copy_of_v1 == {1, 20, 3} now
std::cout << (v1 == copy_of_v1) << '\n'; // Prints 0, for false
Use cases for references.
References have three big use cases:
- Avoiding a copy by storing/using a reference
- Getting additional information out of a function (by passing it a reference, and letting it modify the reference)
- Writing data structures / container classes
We've seen the first case already, so let's look at the other two.
Using references to write functions that modify their input. Let's say you wanted to add the ability to append elements to vectors using +=. An operator is a function, so if it's going to modify the vector, it needs to have a reference to it:
// We take a reference to the vector, and return the same reference
template<class T>
std::vector<T>& operator +=(std::vector<T>& vect, T const& thing) {
vect.push_back(thing);
return vect;
}
This allows us to append elements to the vector just like it was a string:
int main() {
std::vector<int> a;
((a += 1) += 2) += 3; // Appends 1, then 2, then 3
for(int i : a) {
std::cout << i << '\n';
}
}
If we didn't take the vector by reference, the function wouldn't be able to change it. This means that we wouldn't be able to append anything.
Using references to write containers.
References make it easy to write mutable containers in C++. When we want to provide access to something in the container, we just return a reference to it. This provides direct access to elements, even primitives.
template<class T>
class MyArray {
std::unique_ptr<T[]> array;
size_t count;
public:
T* data() {
return array.get();
}
T const* data() {
return array.get();
}
MyArray() = default; // Default constructor
MyArray(size_t count) // Constructs array with given size
: array(new T[count])
, count(count) {}
MyArray(MyArray const& m) // Copy constructor
: MyArray(count) {
std::copy_n(m.data(), count, data();
}
MyArray(MyArray&&) = default;// Move constructor
// By returning a reference, we can access elements directly
T& operator[](size_t index) {
return array[index];
}
};
Now, when using MyArray, we can directly change and modify elements, even if they're primitives:
MyArray<int> m(10); // Create with 10 elements
m[0] = 1; // Modify elements directly
m[0]++; // Use things like ++ directly
Using references in c++ is the same as just using the name of the object itself. Therefore, you might consider a reference an alias.
vector<int> vec = {1, 2, 3};
vector<int>& vecRef = vec;
cout << vec.size() << '\n'; // Prints '3'
cout << vecRef.size() << '\n'; // Also prints '3'
It's worth noting that nobody really uses references to simply have another name for an existing object.
They are primarily used instead of pointers to pass objects without copying them.
C++ uses value semantics by default. Objects are values unless you specifically declare them to be references. So:
auto vecCopy = vecRef;
will create a value object called vecCopy which will contain a deep copy of vec since vecRef is an alias for vec. In Python, this would roughly translate to:
import copy
vec = [3, 1, 4, 1, 5]
vecCopy = copy.deepcopy(vec)
Note that it only "roughly" translates to that. How the copy is performed depends on the type of the object. For built-in types (like int and char for example,) it's a straightforward copy of the data they contain. For class types, it invokes either the copy constructor, or the copy assignment operator (in your example code, it's the copy constructor.) So it's up to these special member functions to actually perform the copy. The default copy constructor and assignment operators will copy each class member, which in turn might invoke that member's copy ctor or assignment operator if it has one, etc, etc, until everything has been copied.
Value semantics in C++ allow for certain code generation optimizations by the compiler that would be difficult to perform when using reference semantics. Obviously if you copy large objects around, the performance benefit of values will get nullified by the performance cost of copying data. In these cases, you would use references. And obviously you need to use references if you need to modify the passed object rather than a copy of it.
In general, value semantics are preferred unless there is a reason to use a reference. For example, a function should take parameters by value, unless the passed argument needs to be modified, or it's too big.
Also, using references can increase the risk of running into undefined behavior (pointers incur the same risks.) You can have dangling references for example (a reference that refers to a destroyed object, for example.) But you can't have dangling values.
References can also decrease your ability to reason about what is going on in the program because objects can get modified through references by non-local code.
In any event, it's a rather big subject. Things start to become more clear as you use the language and gain more experience with it. If there's a very general rule of thumb to take away from all this: use values unless there's a reason not to (mostly object size, requiring mutability of a passed function argument, or with runtime polymorphic classes since those require to be accessed through a reference or pointer when that access needs to be polymorphic.)
You can also find beginner articles and talks about the subject. Here's one to get you started:
https://www.youtube.com/watch?v=PkyD1iv3ATU
I would like to create an object, put the object into a vector, and still be able to modify the same object by accessing only the vector. However, I understand that when an object is push_back() to a vector, the object is actually copied into the vector. As a result, accessing the object in the vector will merely access a similar, but different object.
I have a beginner's knowledge in C, so I know that I can create a pointer to the object, and make a vector of pointers. e.g. vector<Object *>. However, it seems as if pointers are discouraged in C++, and references are preferred. Yet, I cannot make a vector of references.
I wish to use only the standard libraries, so boost is off limits to me.
I heard of smart pointers. However, it appears as if there are multiple types of smart pointers. Would it not be overkill for this purpose? If smart pointers are indeed the answer, then how do I determine which one to use?
So my question is: What is the standard practice for creating a vector of references/pointers to objects?
In other words, would like the below (pseudo-)code to work.
#include <iostream>
#include <cstdlib>
#include <vector>
using namespace std;
class Object
{
public:
int field;
};
vector<Object> addToVector(Object &o)
{
vector<Object> v;
v.push_back(o);
v[0].field = 3; // I want this to set o.field to 3.
return v;
}
int main()
{
Object one;
one.field = 1;
cout << one.field << endl; // 1 as expected
Object &refone = one;
refone.field = 2;
cout << one.field << endl; // 2 as expected
vector<Object> v = addToVector(one);
cout << v[0].field << endl; // 3 as expected
cout << one.field << endl; // I want to get 3 here as well, as opposed to 2.
return 0;
}
I would like to create an object, put the object into a vector, and still be able to modify the same object by accessing only the vector. However, I understand that when an object is push_back() to a vector, the object is actually copied into the vector. As a result, accessing the object in the vector will merely access a similar, but different object.
I'm almost certain that this is not what you want or "should" want. Forgive me that direct opening of my answer, but unless you have a very good reason to do this, you probably don't want to do it.
For that - a vector with references - to work you must guarantee that the referenced objects won't get moved nor destructed while you hold references to them. If you have them in a vector, make sure that vector isn't resized. If you have them on the stack like in your example, then don't let the vector of references or a copy of it leave that stack frame. If you want to store them in some container, use a std::list (it's iterators - pointers basically - don't get invalidated when inserting or removing elements).
You already noticed that you cannot have a vector of "real" references. The reason therefore is that references aren't assignable. Consider following code:
int a = 42;
int b = 21;
int & x = a; // initialisation only way to bind to something
int & y = b;
x = y;
b = 0;
After that, the value you obtain from x will be 21, because the assignment didn't change the reference (to be bound to b) but the referenced object, a. But a std::vector explicitly requires this.
You could now set out and write an wrapper around a pointer like ...
template<typename T>
struct my_ref {
T * target;
// don't let one construct a my_ref without valid object to reference to
my_ref(T & t) : target(&t) {}
// implicit conversion into an real reference
operator T &(void) {
return *target;
}
// default assignment works as expected with pointers
my_ref & operator=(my_ref const &) = default;
// a moved from reference doesn't make sense, it would be invalid
my_ref & operator=(my_ref &&) = delete;
my_ref(my_ref &&) = delete;
// ...
};
... but this is pretty pointless since std::reference_wrapper already provides exactly that:
int main (int, char**) {
int object = 21; // half of the answer
vector<reference_wrapper<int>> v;
v.push_back(object);
v[0].get() = 42; // assignment needs explicit conversion of lhs to a real reference
cout << "the answer is " << object << endl;
return 0;
}
(Example live here)
Now one could argue why using a wrapper around a pointer like std::reference_wrapper when one could also directly use a pointer. IMO a pointer, having the ability to be nullptr, changes the semantics of the code: When you have a raw pointer, it could be invalid. Sure, you can just assume that it's not, or put it somewhere in comments, but in the end you then rely on something that's not guaranteed by the code (and this behaviour normally leads to bugs).
If an element of your vector could "reference" an object or be invalid, then still raw pointers aren't the first choice (for me): When you use an element from your vector which is valid, then the object referenced by it is actually referenced from multiple places on your code; it's shared. The "main" reference to the object then should be a std::shared_ptr and the elements of your vector std::weak_ptrs. You can then (thread safe) acquire a valid "reference" (a shared pointer) when you need to and drop it when done:
auto object = make_shared<int>(42);
vector<weak_ptr<int>> v;
v.push_back (object);
// ... somewhere later, potentially on a different thread
if (auto ref = v[0].lock()) {
// noone "steals" the object now while it's used here
}
// let them do what they want with the object, we're done with it ...
Finally, please take my answer with a grain of salt, much of it is based on my opinion (and experience) and might not count as "standard practice".
does the function set::insert saves a pointer to the element or a copy of it. meaning, can I do the following code, or I have to make sure that the pointers are not deleted?
int *a;
*a=new int(1);
set<int> _set;
_set.insert (*a);
delete a;
*a=new int(2);
_set.insert (*a);
delete a;
I gave the example with int, but my real program uses classes that I created.
All STL containers store a copy of the inserted data. Look here in section "Description" in the third paragraph: A Container (and std::set models a Container) owns its elements. And for more details look at the following footnote [1]. In particular for the std::set look here under the section "Type requirements". The Key must be Assignable.
Apart from that you can test this easily:
struct tester {
tester(int value) : value(value) { }
tester(const tester& t) : value(t.value) {
std::cout << "Copy construction!" << std::endl;
}
int value;
};
// In order to use tester with a set:
bool operator < (const tester& t, const tester& t2) {
return t.value < t2.value;
}
int main() {
tester t(2);
std::vector<tester> v;
v.push_back(t);
std::set<tester> s;
s.insert(t);
}
You'll always see Copy construction!.
If you really want to store something like a reference to an object you either can store pointers to these objects:
tester* t = new tester(10);
{
std::set<tester*> s;
s.insert(t);
// do something awesome with s
} // here s goes out of scope just as well the contained objects
// i.e. the *pointers* to tester objects. The referenced objects
// still exist and thus we must delete them at the end of the day:
delete t;
But in this case you have to take care of deleting the objects correctly and this is sometimes very difficult. For example exceptions can change the path of execution dramatically and you never reach the right delete.
Or you can use smart pointers like boost::shared_ptr:
{
std::set< boost::shared_ptr<tester> > s;
s.insert(boost::shared_ptr<tester>(new tester(20)));
// do something awesome with your set
} // here s goes out of scope and destructs all its contents,
// i.e. the smart_ptr<tester> objects. But this doesn't mean
// the referenced objects will be deleted.
Now the smart pointers takes care for you and delete their referenced objects at the right time. If you copied one of the inserted smart pointers and transfered it somewhere else the commonly referenced object won't be delete until the last smart pointer referencing this object goes out of scope.
Oh and by the way: Never use std::auto_ptrs as elements in the standard containers. Their strange copy semantics aren't compatible with the way the containers are storing and managing their data and how the standard algorithms are manipulating them. I'm sure there are many questions here on StackOverflow concerning this precarious issue.
std::set will copy the element you insert.
You are saving pointers into the set.
The object pointed at by the pointer is not copied.
Thus after calling delete the pointer in the set is invalid.
Note: You probably want to just save integers.
int a(1);
set<int> s;
s.insert(a); // pushes 1 into the set
s.insert(2); // pushes 2 into the set.
Couple of other notes:
Be careful with underscores at the beginning of identifier names.
Use smart pointers to hold pointers.
Ptr:
std::auto_ptr<int> a(new int(1));
set<int*> s;
s.insert(a.release());
// Note. Set now holds a RAW pointer that you should delete before the set goes away.
// Or convert into a boost::ptr_set<int> so it takes ownership of the pointer.
int *a;
*a=new int(1);
This code is wrong because you try to use the value stored at address a which is a garbage.
And, every stl containers copy elements unless you use move semantics with insert() and push_back() taking rvalue references in C++0x.
I have a class that has a vector of objects. What do I need to do to return one of this objects and change it outside the class, keeping the changings? Is it possible to do with regular pointers? Is there a standard procedure? (And yes, my background is in Java.)
Your question is a bit vague, but here's an example:
class foo
{
public:
foo()
{
vec.resize(100);
}
// normally would be operator[]
int& get(size_t pIndex)
{ // the return type is a reference. think of it as an alias
return vec[pIndex]; // now the return value is an alias to this value
}
private:
std::vector<int> vec;
};
foo f;
f.get(10) = 5;
// f.get(10) returned an alias to f.vec[10], so this is equivalent to
// f.vec[10] = 5
The FAQ has a nice section on references.
Also, if you're new to C++ don't try learn with online resources. If you haven't got a book, you should, they're really the only good way to learn the language.
If the vector holds pointers to objects any change to one of the objects returned from the vector (or more accurately the object pointed) will affect the instance inside the vector as well.
If you have std::vector where A is your class, you could return a std::vector::iterator.
class A {
public: int a;
};
std::vector<A> v = ...;
std::vector<A>::iterator it = v.begin(); // access to the first element
it = v.begin() + 5; // access to the 5-th element (vector can do random access)
// 'it' can now be used elsewhere
it->a = 0; // changes are reflected in the object inside the vector
*it = A(); // changes the object hold by the vector
Beware, that iterators may be invalidated, if the vector changes!
You need to return either a reference or a pointer to the object.
type &getref(); // "type &" is a reference
type *getptr(); // "type *" is a pointer
The caller will then have access to the underlying object.
But you then need to make sure the object does not move (which can have if a vector has to grow). You may want to think about using a std::list instead.