C++ Use of smart pointers inside STL containers - c++

What is the benefit of using smart pointers inside STL containers ( vectors, maps etc... ) knowing that these containers manages already the memory ?
Example:
std::vector<std::unique_ptr<int>>
instead of
std::vector<int*>

If the objects are pointers it is not enough to manage the memory the pointers occupy. You also need to manage what the pointers point to. It is a good idea to store the objects pointed to instead of the pointers (in case of your example std::vector<int> would be appropriate), however, in case you have polymorphic objects that is not possible.

You can use it when you need to hold an array of references to objects. That way I can sort an array of references without actually moving the objects around in memory.
#include <algorithm>
#include <iostream>
#include <memory>
#include <vector>
int main()
{
std::shared_ptr<int> foo(new int(3));
std::shared_ptr<int> baz(new int(5));
std::vector<std::shared_ptr<int> > bar;
bar.push_back(baz);
bar.push_back(foo);
std::sort(bar.begin(), bar.end(), [](std::shared_ptr<int> a, std::shared_ptr<int> b)
{
return *a < *b;
});
for(int i = 0; i < bar.size(); ++i)
std::cout << *bar[i] << std::endl;
return 0;
}
Prints:
3
5

Related

C++ Using naked, instead of smart pointers

Consider the following code.
#include <iostream>
#include <vector>
#include <memory>
int main() {
std::vector<std::string> vec;
for(int i =0;i<10;i++){
vec.push_back("adsf");
}
std::string* myPoint = &vec[1];
*myPoint = "this works";
std::shared_ptr<std::string> str_ptr = std::make_shared<std::string>(vec[0]);
str_ptr->push_back('this does not push_back to the end of the string stored in at vec[0]');
for(int i =0;i<10;i++){
std::cout << vec[i] << std::endl; //does not print the new value set by str_ptr
}
return 0;
}
What I want here is to update a value in vec through a pointer. As I've understood smart pointers are no good for this task. Is using a naked pointer here, an acceptable alternative?
make_shared does not mean "make this already-existing thing be shared".
It means "make a new shared thing with the following constructor arguments".
You're dynamically allocating a new string that copies vec[0] (i.e. using the copy constructor).
If you want vec[0] to be a shared_ptr<string>, then you need to make it one from the start.

How to make unordered_map<string*, V> hash by value instead of reference?

I have the following
The two equivalent strings bar and bartest do not map to the same value in unordered_map. How can I make this happen?
Of course they don't map to the same value, const string* is a pointer type and since you call new string twice, you end up with two separate objects that don't have memory identity (the pointers are not equal).
What's worse, you leak both of them at the end of your program.
What's (arguably) worse still, owning raw pointers and naked new calls are considered harmful in modern c++.
Luckily it's all fixed with unordered_map<string, int> - no pointers required whatsoever.
Your C++ is in fact "Java-- + C".
Remove all those silly pointers.
All you need is unordered_map<string,int> and use plain values instead of heap-allocated "news"
just do
#include <unordered_map>
#inclide <string>
#include <iostream>
int main()
{
unordered_map<string,int> mymap;
mymap["bar"] = 5;
mymap["bartest"] = 10;
std::cout << mymap["bar"] << ' ' << mymap["bartest"] << '\n';
return 0;
}

Pass vector by reference to constructor of class

I have a class called test with which I want to associate a large vector with in the order of million elements. I have tried doing this by passing a pointer to the constructor:
#include <iostream>
#include <vector>
using namespace std;
class test{
public:
vector<double>* oneVector;
test(vector<double>* v){
oneVector = v;
}
int nElem(){return oneVector->size();}
};
int main(){
vector<double> v(1000000);
cout << v.size() << endl;
vector<double>* ptr;
test t(ptr);
cout << t.nElem()<< endl;
return 0;
}
However, this results in a Segmentation Fault:11, precisely when I try to do t.nElem(). What could be the problem?
This is C++, don't work with raw pointers if you don't absolutely need to. If the goal is to take ownership of a std::vector without copying, and you can use C++11, make your constructor accept an r-value reference, and give it sole ownership of the std::vector that you're done populating with std::move, which means only vector's internal pointers get copied around, not the data, avoiding the copy (and leaving the original vector an empty shell):
class test{
public:
vector<double> oneVector;
test(vector<double>&& v):oneVector(std::move(v)){
}
int nElem(){return oneVector.size();}
};
int main(){
vector<double> v(1000000);
cout << v.size() << endl;
test t(std::move(v));
cout << t.nElem()<< endl;
return 0;
}
If you really want a pointer to a vector "somewhere else", make sure to actually assign ptr = &v; in your original code. Or new the vector and manage the lifetime across test and main with std::shared_ptr. Take your pick.
ptr is not initialized. What you "want" to do is:
test t(&v);
However, I think you'd be better suited with references here (it's in the title of your question after all!). Using references avoids unnecessary syntax (like -> over .) which just unnecessarily hinder the reading of the code as written.
class test
{
std::vector<double>& oneVector;
public:
test(vector<double>& v) : oneVector(v) {}
size_t nElem() const { return oneVector.size(); }
};
ptr is an uninitialized pointer. This unpredictable value gets copied to t.oneVector. Dereferencing it is undefined behavior.
You need your pointer to actually point at a valid vector.
You forgot to give your pointer the desired value, namely the address of the vector:
vector<double>* ptr = &v;
// ^^^^^^
In your code, ptr remains uninitialized, and your program has undefined behaviour.

Is there a way to move data from a vector to a dynamic array?

I use std::vector to do allocation for me in a function.When I'm done, I want to get plain data from it without extra copying. The data ptr will be handled by another class, so I can ditch the vector and I don't have to care if it's valid. Basically, I want to transfer ownership of vector's data. Is there a way to do this?
Transferring ownership is not possible by design of std::vector. However you may extend the lifetime of the vector by making it static and just using the pointer to the first element:
#include <iostream>
#include <vector>
int* getData()
{
static std::vector<int> v;
v.push_back(0);
v.push_back(1);
v.push_back(2);
v.push_back(3);
return v.data(); // pointer to first element, equivalent to &v.front() or &v[0]
}
int main()
{
auto data = getData();
for ( std::size_t i(0); i < 4; ++i )
{
std::cout << data[i] << "\n";
}
}
Demo: http://ideone.com/hsrOeH
As the vector is static, the destructor isn't called at the end of scope (which is the end of the method getData()). Hence it is safe to use the pointer returned by .data() outside of this scope.

unique_ptr pointing always to the same memory area

Consider this code:
using namespace std;
int* get()
{
unique_ptr<int> p (new int[4]);
return p.get();
}
int main(int argc, char **argv)
{
int *arr1=get();
int* arr2=get();
for(int i=0;i<4;i++)
{
arr1[i]=i;
arr2[i]=i*2;
}
for(int i=0;i<4;i++)
cout << arr1[i];
return 0;
}
arr1 and arr2 point to the same area of memory.
So they share the same values.
I don't understand why, when I call arr2=get() :
unique_ptr<int> p (new int[4]);
This object shouldn't be created again? It isn't deleted because still reachable by arr1.
How to get two arrays of different memory areas?
I am fairly sure you are playing with undefined behavior which is bad.
the data being pointed to was destroyed when the unique pointer was destroyed, the fact the values are the same, and the same slot was chosen is luck.
for pointers to array type use a vector
std::vector<int> get()
{
return std::vector<int>(4);
}
int main()
{
std::vector<int> arr1=get();
std::vector<int> arr2=get();
return 0;
}
for normal single value pointers then you can return a unique_ptr;
std::unique_ptr<int> get(){
return std::unique_ptr<int>(new int(0));
}
:::
std::unique_ptr<int> ptr=get();
There are a memory leak in such kind of usage of smart pointers. unique_ptr will use operator delete in order to free the allocated memory, but you need delete []. Also the return value of get function will be an invalid ptr because the unique_ptr will free the allocated area. If you need dynamically allocated arrays then use std::vector.