In a function I get as an argument the reference to a vector:
void myFunc (vector< int>& myRef) {...}
Now in this function I need to backup (because myRef will become something else) the reference to that particular vector:
vector< int>& myBackup = myRef
Now I want myRef to become a reference to a NEW COPY of that vector. How do I do that?
Can I just say
vector< int> myRef = myBackup
?
Is the result myBackup = a reference to the original object and myRef = a reference to a copy of the original object?
C++ references cannot be changed to refer to new objects after they are initially assigned. If you need that kind of behavior, you have to use a pointer.
Does this code compile? You should really make use of a pointer here, if you want to reassign, as references can't be reassigned. A simple rule of thumb is if you want to be able to reassign the variable use a pointer, so long as it is advisable to do so in the current situation.
For example:
void myFunction(std::vector<int*> myPtr) {}
To solve this problem you need to make deep copy
You can use memcpy but it is not a safe way;
or such as
vector<int> newVector;
newVector.reserve(myRef.size()); //for performance, to avoid realloc
for (vector< int>::iterator it = myRef.begin();it!=myRef.end();++it)
newVector.push_back(*it);
myRef = newVector;
And after this line
vector< int>& myBackup = myRef
you have a compiler error with redeclaration of myRef...
Related
I have the below bit of code:
map<int,int>& myMap = new map<int,int>();
but I get the following compiler error:
no suitable constructor exists to convert from "std::map<int,int, std::less<int>, std::allocator<std::pair<const int, int>>>*" to "std::map<int,int, std::less<int>, std::allocator<std::pair<const int, int>>>".
Does this mean I have to do:
map<int,int>& myMap = *new map<int,int>();
I thought that objects could passed to references without dereferencing first (as opposed to pointers)? Also I know smart pointers exist but I'm not trying to use those for now.
You can use
map<int,int>& myMap = *new map<int,int>();
but I don't recommend it.
The dynamically allocated memory has to be deallocated. At that time, you will need to use something along the lines of
delete &myMap;
That is poor quality code, IMO.
Use a smart pointer if you need dynamically allocated memory.
std::shared_ptr<map<int,int>> ptr = new map<int,int>();
If you need to use a reference, you can use:
map<int,int>& myMap = *ptr;
It will better if you can avoid dynamically allocated object altogether and use an automatic object (object in stack memory).
map<int,int> myMap;
Update, in response to OP's comment
In a comment you said
Yeah i want to keep that reference because im passing it to a recursive function
The C++ way to deal with it is to pass an object by reference.
void recursive_foo(std::map<int, int>& myMap)
{
}
void foo_user()
{
std::map<int, int> myMap;
// Fill up myMap
// ...
recursive_foo(myMap);
}
If the recursive function does not modify the object, you can follow the idiom used by the standard library and use iterators instead.
void recursive_foo(std::map<int, int>::iterator start,
std::map<int, int>::iterator end)
{
}
void foo_user()
{
std::map<int, int> myMap;
// Fill up myMap
// ...
recursive_foo(myMap.begin(), myMap.end());
}
I thought that objects could passed to references without dereferencing first (as opposed to pointers)?
Yes objects can be passed, but what you have here:
map<int,int>& myMap = new map<int,int>();
is not an object but reference which you try to initialize by pointer to dynamically allocated object. Just create object:
map<int,int> myMap;
and it should work fine.
To make things clear, you mixed different concepts, lets say we have a function that accepts variable of sometype by reference:
void func( sometype &ref ) { ... }
it does not mean you have to declare variable as reference to pass it there, you can pass automatic object:
sometype auto_object;
func( auto_object );
or pass dynamically allocated one:
sometype *ptr_to_object = new sometype;
func( *ptr_to_object );
delete ptr_to_object; // or better use smart pointer
and if you do not need this object to outlive scope where you use it it is preferable to use first variant.
I have a vector pointer that points to a vector<object> so
const std::vector<object> vecPtr* = &vec;
Now i'd like to fill in this manner std::multimap<std::string, object*> dataMap; where the key is object.name and value is pointer to an object.
I tried
for(std::vector<object>::const_iterator it = data->cbegin(); it != data->cend(); ++it){
dataMap.insert(std::pair<std::string, object*>(it->name, &it));
}
but i get an error.
error: no matching function for call to 'std::pair<std::basic_string<char>, object*>::pair(const string&, std::vector<object>::const_iterator*)'
dataMap.insert(std::pair<std::string, object*>(it->name, &it));
^
What am i doing wrong?
I know i complicating my life with pointers, but I want to avoid copying objects
In order to avoid copying objects consider to use reference of objects. Moreover, consider to use shared pointer such as std::shared_ptr (for C++11), or boost::shared_ptr. A good style is to avoid allocating memory manually. Let's do it in an automatic way provided by the STL.
class Object{};
typedef boost::shared_ptr < Object > ObjectPtr;
then
std::multimap < std::string, ObjectPtr > map;
Creating instances of Object just use:
ObjectPtr obj = boost::make_shared < Object > ();
&it is a pointer to iterator, not to an object. If you want to get a pointer to an object, write &*it.
After that you'll see an error saying that you can't convert from const object* to object* - this is because you are using const_iterator. So, depending on what you need, you can do two things.
Either declare dataMap as std::multimap<std::string, const object*> dataMap;, if you are not planning to change the objects in it.
Or use iterator:
for (std::vector<object>::iterator it = data->begin(); it != data->end(); ++it) {
dataMap.insert(std::pair<std::string, object*>(it->name, &*it));
}
By the way, this loop can be rewritten as:
for (auto& a : *data) {
dataMap.insert({a.name, &a});
}
Say I have an std::map type which for example is defined as follows.
std::map<int, int>* someMap;
If I weren't using a pointer, I could simply add an element using the index operator. However in this case, since I have a pointer, would the following be the correct way to insert using the index operator.
(*someMap)[someIndex] = someValue;
Yes. The operator [] is overloaded for the Map class. It has to be used directly with the object.
Make sure you point someMap at something. Otherwise, its just contains a meaningless address derived from garbage on the stack. Here's an example allocating from the heap:
std::map<int, int>* someMap = new std::map<int, int>();
and once thats done, yes, you are correct in how to use it:
(*someMap)[someIndex] = someValue;
and be sure to cleanup after yourself
delete someMap;
Yes, your code is fine:
(*someMap)[someIndex] = someValue;
Simple question, I just want to initialize a map to be empty, instead of being a nullptr.
const std::map<std::string, std::string>* emptyDictionary;
I tried
const std::map<std::string, std::string>* emptyDictionary = {"", ""};
but obviously that's not right.
Thanks guys.
You forgot to make any map at all -- you just made a pointer! You can make the pointer point to a dynamically allocated map:
const std::map<std::string, std::string>* emptyDictionary
= new std::map<std::string, std::string>;
This map will be truly empty. If you add the initializer {{"", ""}}, which you may well do, then you don't actually have an empty map, but rather a map with one element which maps an empty string to an empty string.
Note that you can never modify your map through the const pointer, so it's a bit questionable why you'd want to do this.
Note also that wanton dynamic allocation is generally a poor programming style. There's almost surely a better way to do whatever you need to do, or, based on your comment, you're just grossly misunderstanding something: The best way to obtain a pointer is to take the address of an existing object:
std::map<std::string, std::string> m;
foo(&m); // pass address of m as a pointer
const std::map<std::string, std::string>* emptyDictionary
= new std::map<std::string, std::string>();
The default (empty) constructor of map will create an empty map http://www.cplusplus.com/reference/stl/map/map/.
Either declare the map with automatic allocation on the stack by just writing
std::map<std::string, std::string> emptyDictionary();
And send it to your function using the addres-off operator
yourfunction(&emptyDictionary);
However, if the dictionary will outlive the instance of it was created, you need to dynamically allocate it instead to avoid a call to its destructor.
const std::map<std::string, std::string>* emptyDictionary = new std::map<std::string, std::string>();
Then you dont need the address-of operator when calling your function.
yourfunction(emptyDictionary);
However, the responsibility of deallocation will then be yours. When you dont need the object any longer, you need to delete the object using the delete statement.
delete emptyDictionary;
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.