nested unique_ptr and stl containers - c++

I have recently read about RAII and have begun using it. I am trying to define graph as adjacency list and allocate the entire DS on heap using unique_ptr. I know that I can define them as stack objects, but I am trying to use unique_ptr's to get used to them.
I am doing the following
unique_ptr to vector --
|-->(unique_ptr)list<edge>
|-->(unique_ptr)list<edge>
|-->(unique_ptr)list<edge>
|-->(unique_ptr)list<edge>
Code:
#include<memory>
#include<vector>
#include<list>
using namespace std;
struct edge {
int vertex;
int weight;
};
int vertices = 10;
unique_ptr<vector<unique_ptr<list<struct edge > > > >
adj_list(new vector<list<struct edge> >(10)); // THIS COMPILES
unique_ptr<vector<unique_ptr<list<struct edge > > > >
adj_list(new vector<list<struct edge> >(10, new list<edge>())); //THIS GIVES COMPILATION ERROR
Can anyone help me correct this?
EDIT:
I have doubt regarding vector being RAII classes.
if I do the following
vector<int> *v;
v = new vector<int> (10);
Do I have to delete the variable v. Or will it automatically free the memory on heap, when it goes out of scope ?
EDIT:
using pointer to vector makes the user responsible for memory management.

Your unique_ptrs are unnecessary. Just use the objects themselves:
vector<list<edge>> adj_list;
RAII does not imply smart pointers, it's the other way around. C++ accomodated RAII long before smart pointers.

Look at vector's constructors here. None of them accepts a pointer to the element. So either use vector<list<struct edge>*> or change the call to this:
list<struct edge> emptyList;
... (new vector<list<struct edge> >(10, emptyList));

Related

Is it possible to allocate in private memory space an object made for boost managed shared memory?

Let's say I typedef a vector to be used in boost shared memory. When creating it, I have to give an allocator from a managed_shared_memory, which makes sense.
If I want to use this same vector type but to allocate it not in shared memory but instead allocating it on the standard process memory space.
Is it possible by giving a different allocator to the object ?
Do I have to change the definition of my vector to be able to accept both implementations ?
Is it impossible to do and therefore I should use a different kind of vector instead ?
Sample code I am trying to fix :
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
using namespace boost::interprocess;
typedef managed_shared_memory::segment_manager SegmentMgr;
typedef allocator<int, SegmentMgr> IntAlloc;
typedef vector<int, IntAlloc> IntVector;
int main()
{
shared_memory_object::remove("Boost");
managed_shared_memory managed_shm{ open_or_create, "Boost", 1024 };
IntAlloc intAlloc = managed_shm.get_segment_manager();
IntVector vectorInSharedMemory({}, intAlloc); // <--- this allocates in shared memory
IntVector vectorInMyOwnPrivateMemorySpace({}, /* ? */); // <--- is there a trick here ?
return 0;
}
I want to use this same vector type but to allocate it not in shared memory
Let's stop right there. It is not the same vector anymore. Given that the allocator is a template parameter of vector, different allocators means different types.
It is as simple as saying std::vector<int> and std::vector<double> are not even the same type.
Do I have to change the definition of my vector to be able to accept both implementations ?
Yes you can use alias declarations to specify that IntVector is a vector of int of parametrized allocator.
template<typename Alloc> using IntVector=vector<int, Alloc>; // template definition
// [...]
IntVector<IntAlloc> sharedMemoryVector;
IntVector<std::allocator<int>> localHeapVector;
Yes. I have given an extended answer about this before:
boost::interprocess Containers of containers NOT in shared memory and the followup boost::interprocess scoped_allocator AND Containers of containers NOT in shared memory
making non-shared copies of boost::interprocess shared memory objects
What you call "private memory" is "the local heap" though. You can also have mapped memory with MAP_PRIVATE, which means something else (see mmap and e.g. Opening managed shared memory and mapped files with Copy On Write or Read Only modes)
You need to create an allocator class which can be switched at runtime to use either allocator. E.g. something like this (not a complete example but just to give you the idea):
template < typename T >
class switchable_allocator
{
boost::interprocess::allocator< T, SegmentMgr >* sharedAllocator;
std::allocator< T > privateAllocator;
public:
switchable_allocator(boost::interprocess::allocator< T, SegmentMgr >* sharedAllocator) : sharedAllocator(sharedAllocator) {}
pointer allocate(size_t n)
{
if (sharedAllocator)
{
return sharedAllocator->allocate(n);
}
return privateAllocator.allocate(n);
}
};

How to avoid memory leaks, with C++ with STL containers?

code snippet below:
//container declared
map<string, structA*>& aMap;
// allocation and insertion to container
structA *item = new structA();
aMap["arrDevAddr"] = item;
However I iterate and free the map value (pointer) at the end of the map getting used.
Now, due to above code snippet, valgrind is flagging me as "definitely leaked" message.
I want to clarify, the general principle of coding to avoid memory leak. As per my understanding, in (C++ coding):
when we allocate a memory, we are entitled to free it aswell, limted by the overall span of code.
when we keep the allocated memory in some container (e.g. map here), we still need to retain those pointers (allocations), until the map is using those pointers.
which means, allocate >> add pointer to container >> usage of pointers in the map >> ensure "deleting/freeing" the struct-pointers, when the map use is over, or if the map is contained in some object, then in the object's "destructor", map should be iterated and struct-pointers should be freed.
correct me, if I am wrong in my understanding.
SECOND CASE:
class A{
...
map<string, structA*>& aMap;
...
}
now in some other class, the map is inserted with value as;
if(..)
{ structA item;
aObj->aMap["arrDevAddr"] = &item;
}
...
Now, in this case, as "item" is local to the scope, will the map be containing the "dangling references"? If not, how?
In such scenario's what should be the way to ensure, we avoid any memory-leaks while coding?
Don't delete or free things yourself. Always use a memory-managing class- these are completely immune to memory leaks and such related problems unless you work very hard to do something very stupid.
In this case something like unique_ptr would be fine, or even just storing structA by value.
You would avoid memory leaks by storing a std::unique_ptr rather than a raw pointer:
#include <iostream>
#include <map>
#include <memory>
#include <string>
struct structA {};
using structA_ptr = std::unique_ptr<structA>;
//container declared
std::map<std::string, structA_ptr> aMap;
using namespace std;
int main()
{
aMap.emplace("bob", structA_ptr { new structA {} });
return 0;
}

initialization new map and set in c++

Hi i am doing my homeworks and i have a problem.
I need diferents maps and set in the application and i want reuse some variables.
I have this global variables
map<char,set<char> > IAF; //I Am Father
map<char,int> NBM; //Number Before Me
set<char> WCR; //Who can run
and every time in the main i need reset this variables.
I have done two things:
IAF = new map<char,set<char> >;
and
IAF = map<char,set<char> >;
But any has run.
Can someone help me?
use
IAF.clear()
NBM.clear()
WCR.clear()
(Edit: references to the spec and caveats)
map::clear()
set::clear()
Note that if you're storing pointers, clear() will remove the pointers, but it will not delete the memory pointed to by the pointers.
map<char,set<char> > IAF;
This is a definition of variable. This is not a pointer. If you want to do some kind of initialization you can use one of supported methods, e.g:
std::copy( differentContainer.begin(), differentContainer.end(), IAF.begin());
or
while( ...) {
IAF.insert( ...);
// or
IAF[ key] = value;
}
To delete the content of map you can do (this will not automatically delete memory pointed to by pointer in map - if you store pointers, use a smart pointers then):
IAF.clear();
In addition to the previous answers which are fairly clear. The new keyword, that you used at some point, is to allocate memory for a pointer.
map<char, set<char> > *IAF = new map<char, set<char> >;
//...
// free the memory
delete IAF;
Check the Dynamic memory allocation for more information and to understand when and how to use pointers.
Also, using
IAF = map<char,set<char> >;
Is incorrect. The map<char, set<char> > is a class name (combined with templates generic programming, see the answer to What is the meaning of "generic programming" in c++? ) and hence you cannot assign it to a variable in this way. What you want to do is to call the constructor that will return an instance of that class:
IAF = map >();
However, doing it this way is not efficient at all. It creates a temporary object, destroys IAF, copies the temporary, and then destroys the temporary (unless you are using C++11 and in this case you use move, but still...). So, it's better to use the clear() as stated by the other answers.

Adding an element <string, pointer> to boost unordered hashmap

I am using boost unordered hashmap in C++ and I am unable to add elements to my hash map (my program has a segmentation fault). I am very new to C++ and the majority of my code (except the hash map handling) is C code. Could you please point out the problem.
// my simplified code
struct Record
{
char *data;
};
typedef boost::unordered_map<std::string, std::vector<Record*> > MAP;
typedef std::pair<std::string,std::vector<Record*> > PAIR;
struct OuterRelation
{
short num_keys;
short join_key_ndx;
MAP hash_table;
};
OuterRelation *outer_relation = (OuterRelation *) malloc (sizeof(OuterRelation)) ;
Record *new = (Record *) malloc(sizeof(Record));
new->data = "somestring";
outer_relation->hash_table[new->data].push_back(new);
The problem is in the last line.
STOP USING malloc. That's for C. Correct syntax would be:
OuterRelation *outer_relation = new OuterRelation;
Your use of malloc has allocated enough space for the OuterRelation struct alone. This might be enough if the struct contained only plain-old-data. However, the hash_table member is a class and using malloc has left it uninitialised.
new is (at its most basic) a combination of malloc and a call to the new'd object's constructor. The constructor for your struct will in turn call the constructors of its members, including the map. The map's constructor will initialise its data members.
You also need to stop using new as a variable name. That clashes with the new C++ keyword.

std::set for each element in an array

I need a functionality of std::set for each element in an array. How can I achieve this functionality?
I started with allocating dynamic array of std set in C++ as follows:
set<int>* entry;
followed by allocation:
entry = (set<int>*)malloc(sizeof(set<int>)*32);
No compilation problem, but the runtime fails with segmentation fault when any element is accessed:
entry[0].insert(23);
Any help is highly appreciated.
What about
#include <set>
#include <vector>
int main()
{
std::vector < std::set<int> > entry(32); // std::vector constructor makes 32 calls to std::set<int> constructor
entry[0].insert(23);
// std::vector destructor makes 32 calls to std::set<int> destructor
}
In c++ you allocate memory with new. The difference from malloc here is that the constructor is called to initialize the memory.
entry = new set<int>[32];
Even though you've allocated storage for 32 std::set's you haven't initalized this span of memory (ie. the constructor of your std::set's has not been called) therefore the memory you are trying to operate on/access in entry[0].insert (23) will cause undefined behavior.
Mixing C++ objects with malloc and it's equivalent is normally (I'm tempted to write "always") considered to be bad practice.
Instead turn to operator new which will allocate memory and handle construction of your object in a proper manner, also remember to delete the memory allocated to release the memory back to your system (and make the object(s) destruct in a true manner).
The proper way to do it in C++
Some answers will contain text saying that you are better of using a std::vector<std::set>, though that isn't really an answer to your question so I'll leave you with this example snippet
int
main (int argc, char *argv[])
{
std::set<int> *entries = new std::set<int> [32];
entries[0].insert (123);
delete [] entries;
}
This is a good question, whose answer is not immediately obvious. The trouble is that each set object wants to be initialized before it is used, whereas your code only allocates raw memory for each set. This fixes it:
#include <vector>
#include <set>
using std::vector;
using std::set;
const int N = 32;
int main() {
vector< set<int> > entry(N);
entry[0].insert(23);
return 0;
}
Not try to use malloc/calloc/realloc etc with c++ classes. Use new.