Is it legal to have a vector of references to objects, like the following?
vector<Agent&> seenAgents;
Which would for example be populated by some, but not all of the objects in the scene?
I have a vector of Agent objects, but the vector outlined above should hold references to only the ones each agent can currently see - meaning that the references will be being added and removed all the time.
Is this something the language will allow? And in addition, is there anything else I need to be aware of? If I remove a reference from the vector does it persist anywhere? Is it a memory leak?
I seem to be getting this error on the line declaring the vector:
error C2528: 'pointer' : pointer to reference is illegal
Is this something directly to do with the line or is it most likely occurring somewhere else? It's being initialised in the constructors initialiser list like this:
seenAgents(vector<Agents&>())
You can't have vector of references, as a reference is not copyable assignable and all STL containers are supposed to store copyable assignable items.
But you can make the container to hold pointers. Like this:
vector< Agents* > seenAgents;
This is a little dangerous. You need to be sure that these pointers will remain valid. I mean - if someone deletes an object, pointed by a pointer in this container, the pointer becomes invalid. You need to be sure that this will not happen, because you can't check it (you can't check for NULL, because a pointer will not become NULL, if someone deletes the pointed object).
The best solution here (provided by container with pointers) would be to use some smart pointers - some with reference count, for example; they will guarantee you that the object will exist and that the pointer is valid. And in case that the object, pointed by the smart pointer, is destroyed, you can check it for NULL.
You can use std::reference_wrapper instead in C++11:
std::reference_wrapper is a class template that wraps a reference in a copyable, assignable object. It is frequently used as a mechanism to store references inside standard containers (like std::vector) which cannot normally hold references.
Example:
#include <functional>
#include <vector>
#include <iostream>
int main(int argc, char *argv[])
{
int a = 5;
int b = 6;
std::vector<std::reference_wrapper<const int>> v;
v.push_back(a);
v.push_back(b);
for (const auto& vi: v)
{
std::cout << vi << std::endl;
}
return 0;
}
https://en.cppreference.com/w/cpp/utility/functional/reference_wrapper
You can't do it. Use pointers.
The Boost library provides PTR_VECTOR which is a better solution than:
vector<T*> foo;
I wanted similar functionality. In the end, here is what I did:
template <class T> class VectorOfRefs : public std::vector<T *> {
public:
inline T & at( const uint64_t i ) {
T * x = std::vector<T *>::at( i );
return *x;
}
};
VectorOfRefs < MyType > myVector;
myVector.push_back( &myInstance0 );
myVector.push_back( &myInstance1 );
// later in the code:
myVector.at( i ).myMethod();
Obviously this is a vector of pointers underneath the covers.
Normally I would use STL and settle for myVector.at( i )->myMethod(), but I wanted to use the ++ operator, so I had the following two options:
// using STL:
(*myVector.at(i))++;
// or, using my wrapper:
myVector.at( i )++;
I find the notation with the wrapper far preferable in terms of code readability. I don't like the wrapper, per se, but it pays dividends later.
Related
I am working on a 2-dimensional vector (vector of vector) to carry some pointers in C++.
std::vector< std::vector<object*> > data;
here object is a class and each entry of data carries a pointer to an object instance. I make it work in C++ but the memory management makes it hard to maintain when I apply it to other code. I did some research and someone suggests using a smart pointer instead. I try the following code
#include <vector>
#include <memory>
using namespace std;
int main(void) {
vector< int > source = {1,2,3,4,5};
vector< auto_ptr<int> > co;
vector< vector< auto_ptr<int> > > all;
co.push_back( auto_ptr<int>(&source[0]) );
co.push_back( auto_ptr<int>(&source[2]) );
co.push_back( auto_ptr<int>(&source[4]) ); // it works well up to here
all.push_back(co); // but it crashs here
return 0;
}
One of the error messages is
C:/msys64/mingw64/include/c++/9.2.0/bits/stl_construct.h:75:7: error: no matching function for call to 'std::auto_ptr::auto_ptr(const std::auto_ptr&)'
75 | { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I wonder in what way I could add the vector< auto_ptr<int> > to another vector or list?
First, don't use std::auto_ptr. As you've found out, it cannot be used as an element of a vector, because it doesn't have an appropriate copy constructor. It has been deprecated since C++11 in favour of using std::unique_ptr instead. std::auto_ptr was removed from the language in C++17.
Second, objects pointed by &source[i] are owned by source. The objects aren't owned by the raw pointer that results from that expression, and there isn't even a way to transfer their ownership. As such, you mustn't give their ownership to a smart pointer. If you do, the behaviour of the program will be undefined as soon as those smart pointers are destroyed.
If you want to have a vector of vectors of smart pointers, here is a correct example:
std::vector<std::unique_ptr<int>> co;
std::vector<std::vector<std::unique_ptr<int>>> all;
for (auto i : source) {
co.push_back(std::make_unique<int>(i));
}
all.push_back(std::move(co));
Bonus hints:
Unless you need to swap the rows, it is more efficient to use a single dimensional vector to represent a 2 dimensional array than to use a vector of vectors.
Unnecessary dynamic allocation can be expensive. Given that the vector elements themselves are already in dynamic storage, it is often best to store objects directly as elements instead of allocating them separately and storing smart pointers.
auto_ptr<T> is something you should never use. It has serious and unfixable design flaws. One of them is you cannot use it in a vector.
It was depricated and removed from the C++ standard for a reason.
Use std::unique_ptr<T>.
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".
struct A
{
};
int main()
{
A *a = new A;
std::unordered_map<int, A*&> hash;
hash.insert(make_pair(1, a)); //error
}
What is the syntax to make this work?
If I do this:
a = new A;
I want the hashmap to point to the new object.
hash.insert(std::pair< int , A*&>(1, a));
In your example, the return type of std::make_pair is std::pair<int, A*> instead of std::pair<int, A*&> (due to template argument deduction).
This does the trick:
hash.insert(std::make_pair<int, A*&>(1, a)); //no error
Note that it is uncommon to store references to maps and other data structures. Think if you really need it.
This question misses the point of value-semantics that is inherent in the design of STL.
Value-semantics implies
Values are stored and copied into containers (including pointers), not references.
When you insert something into a container, a copy is made and stored, even if what you pass in is a reference variable.
This implies you can't have constructs like a std::vector<> of references.
In your specific example, omit the reference symbol (&) and you are fine (besides the memory leak).
Storing a pointer in stl is cheap so you don't have to worry about cost of copying the pointer.
But, as always in C++, you do have to concern yourself with cleanup (if you don't use smart pointers) and object lifetimes.
I'd much prefer to use references everywhere but the moment you use an STL container you have to use pointers unless you really want to pass complex types by value. And I feel dirty converting back to a reference, it just seems wrong.
Is it?
To clarify...
MyType *pObj = ...
MyType &obj = *pObj;
Isn't this 'dirty', since you can (even if only in theory since you'd check it first) dereference a NULL pointer?
EDIT: Oh, and you don't know if the objects were dynamically created or not.
Ensure that the pointer is not NULL before you try to convert the pointer to a reference, and that the object will remain in scope as long as your reference does (or remain allocated, in reference to the heap), and you'll be okay, and morally clean :)
Initialising a reference with a dereferenced pointer is absolutely fine, nothing wrong with it whatsoever. If p is a pointer, and if dereferencing it is valid (so it's not null, for instance), then *p is the object it points to. You can bind a reference to that object just like you bind a reference to any object. Obviously, you must make sure the reference doesn't outlive the object (like any reference).
So for example, suppose that I am passed a pointer to an array of objects. It could just as well be an iterator pair, or a vector of objects, or a map of objects, but I'll use an array for simplicity. Each object has a function, order, returning an integer. I am to call the bar function once on each object, in order of increasing order value:
void bar(Foo &f) {
// does something
}
bool by_order(Foo *lhs, Foo *rhs) {
return lhs->order() < rhs->order();
}
void call_bar_in_order(Foo *array, int count) {
std::vector<Foo*> vec(count); // vector of pointers
for (int i = 0; i < count; ++i) vec[i] = &(array[i]);
std::sort(vec.begin(), vec.end(), by_order);
for (int i = 0; i < count; ++i) bar(*vec[i]);
}
The reference that my example has initialized is a function parameter rather than a variable directly, but I could just have validly done:
for (int i = 0; i < count; ++i) {
Foo &f = *vec[i];
bar(f);
}
Obviously a vector<Foo> would be incorrect, since then I would be calling bar on a copy of each object in order, not on each object in order. bar takes a non-const reference, so quite aside from performance or anything else, that clearly would be wrong if bar modifies the input.
A vector of smart pointers, or a boost pointer vector, would also be wrong, since I don't own the objects in the array and certainly must not free them. Sorting the original array might also be disallowed, or for that matter impossible if it's a map rather than an array.
No. How else could you implement operator=? You have to dereference this in order to return a reference to yourself.
Note though that I'd still store the items in the STL container by value -- unless your object is huge, overhead of heap allocations is going to mean you're using more storage, and are less efficient, than you would be if you just stored the item by value.
My answer doesn't directly address your initial concern, but it appears you encounter this problem because you have an STL container that stores pointer types.
Boost provides the ptr_container library to address these types of situations. For instance, a ptr_vector internally stores pointers to types, but returns references through its interface. Note that this implies that the container owns the pointer to the instance and will manage its deletion.
Here is a quick example to demonstrate this notion.
#include <string>
#include <boost/ptr_container/ptr_vector.hpp>
void foo()
{
boost::ptr_vector<std::string> strings;
strings.push_back(new std::string("hello world!"));
strings.push_back(new std::string());
const std::string& helloWorld(strings[0]);
std::string& empty(strings[1]);
}
I'd much prefer to use references everywhere but the moment you use an STL container you have to use pointers unless you really want to pass complex types by value.
Just to be clear: STL containers were designed to support certain semantics ("value semantics"), such as "items in the container can be copied around." Since references aren't rebindable, they don't support value semantics (i.e., try creating a std::vector<int&> or std::list<double&>). You are correct that you cannot put references in STL containers.
Generally, if you're using references instead of plain objects you're either using base classes and want to avoid slicing, or you're trying to avoid copying. And, yes, this means that if you want to store the items in an STL container, then you're going to need to use pointers to avoid slicing and/or copying.
And, yes, the following is legit (although in this case, not very useful):
#include <iostream>
#include <vector>
// note signature, inside this function, i is an int&
// normally I would pass a const reference, but you can't add
// a "const* int" to a "std::vector<int*>"
void add_to_vector(std::vector<int*>& v, int& i)
{
v.push_back(&i);
}
int main()
{
int x = 5;
std::vector<int*> pointers_to_ints;
// x is passed by reference
// NOTE: this line could have simply been "pointers_to_ints.push_back(&x)"
// I simply wanted to demonstrate (in the body of add_to_vector) that
// taking the address of a reference returns the address of the object the
// reference refers to.
add_to_vector(pointers_to_ints, x);
// get the pointer to x out of the container
int* pointer_to_x = pointers_to_ints[0];
// dereference the pointer and initialize a reference with it
int& ref_to_x = *pointer_to_x;
// use the reference to change the original value (in this case, to change x)
ref_to_x = 42;
// show that x changed
std::cout << x << '\n';
}
Oh, and you don't know if the objects were dynamically created or not.
That's not important. In the above sample, x is on the stack and we store a pointer to x in the pointers_to_vectors. Sure, pointers_to_vectors uses a dynamically-allocated array internally (and delete[]s that array when the vector goes out of scope), but that array holds the pointers, not the pointed-to things. When pointers_to_ints falls out of scope, the internal int*[] is delete[]-ed, but the int*s are not deleted.
This, in fact, makes using pointers with STL containers hard, because the STL containers won't manage the lifetime of the pointed-to objects. You may want to look at Boost's pointer containers library. Otherwise, you'll either (1) want to use STL containers of smart pointers (like boost:shared_ptr which is legal for STL containers) or (2) manage the lifetime of the pointed-to objects some other way. You may already be doing (2).
If you want the container to actually contain objects that are dynamically allocated, you shouldn't be using raw pointers. Use unique_ptr or whatever similar type is appropriate.
There's nothing wrong with it, but please be aware that on machine-code level a reference is usually the same as a pointer. So, usually the pointer isn't really dereferenced (no memory access) when assigned to a reference.
So in real life the reference can be 0 and the crash occurs when using the reference - what can happen much later than its assignemt.
Of course what happens exactly heavily depends on compiler version and hardware platform as well as compiler options and the exact usage of the reference.
Officially the behaviour of dereferencing a 0-Pointer is undefined and thus anything can happen. This anything includes that it may crash immediately, but also that it may crash much later or never.
So always make sure that you never assign a 0-Pointer to a reference - bugs likes this are very hard to find.
Edit: Made the "usually" italic and added paragraph about official "undefined" behaviour.
I've always been a bit confused about how STL containers (vector, list, map...) store values. Do they store references to the values I pass in, or do they copy/copy construct +store the values themselves?
For example,
int i;
vector<int> vec;
vec.push_back(i);
// does &(vec[0]) == &i;
and
class abc;
abc inst;
vector<abc> vec;
vec.push_back(inst);
// does &(vec[0]) == &inst;
Thanks
STL Containers copy-construct and store values that you pass in. If you want to store objects in a container without copying them, I would suggest storing a pointer to the object in the container:
class abc;
abc inst;
vector<abc *> vec;
vec.push_back(&inst);
This is the most logical way to implement the container classes to prevent accidentally storing references to variables on defunct stack frames. Consider:
class Widget {
public:
void AddToVector(int i) {
v.push_back(i);
}
private:
vector<int> v;
};
Storing a reference to i would be dangerous as you would be referencing the memory location of a local variable after returning from the method in which it was defined.
That depends on your type. If it's a simple value type, and cheap to copy, then storing values is probably the answer. On the other hand, if it's a reference type, or expensive to copy, you'd better store a smart pointer (not auto_ptr, since its special copy semantics prevent it from being stored in a container. Go for a shared_ptr). With a plain pointer you're risking memory leakage and access to freed memory, while with references you're risking the latter. A smart pointer avoids both.