C++: Create a new object with a reference variable - c++

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

c++ references to heap objects?

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.

Store pointers to an object in map

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});
}

Inserting an element with pointer to std::map using Index operator

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;

How to initialize a constant map pointer to be empty in C++?

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 mis­under­stand­ing 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;

Insert reference to pointer into an map

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.