4

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.

TemplateRex
  • 69,038
  • 19
  • 164
  • 304
lashgar
  • 5,184
  • 3
  • 37
  • 45

5 Answers5

11

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
}
TemplateRex
  • 69,038
  • 19
  • 164
  • 304
5

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];
Karolis Juodelė
  • 3,708
  • 1
  • 19
  • 32
  • 4
    But don't forget to delete it when you've finished with it. Usually, it's better to use a container like `std::vector` to manage the memory for you. – Mike Seymour Jul 04 '12 at 12:05
4

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;
}
Community
  • 1
  • 1
Filip Roséen - refp
  • 62,493
  • 20
  • 150
  • 196
  • 4
    `std::vector` really is an answer to the question. Your example has a memory leak if `insert` throws an exception; the simplest fix for such a leak is to manage the array with a RAII wrapper; and such a wrapper for a dynamic array is already implemented and called `std::vector`. – Mike Seymour Jul 04 '12 at 12:11
  • @MikeSeymour it's an answer beyond the scope of the question, therefore I choose not to include it in my post. – Filip Roséen - refp Jul 04 '12 at 12:36
  • MikeSeymour is right. This is no longer good practice in C++. `std::array` is another option for fixed size arrays. – Neil G Aug 09 '12 at 15:27
2

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;
}
thb
  • 13,796
  • 3
  • 40
  • 68
1

Not try to use malloc/calloc/realloc etc with c++ classes. Use new.

ForEveR
  • 55,233
  • 2
  • 119
  • 133