0

I am working on a bitset implementation. The bitset uses an array of unsigned long long to store the bits.

class bitset{
    typedef unsigned long long uint64;
    uint64* bits;
    ...
}

Since I need this bitset to store a large about of data, I am finding that it works best when I initialize the array of uint64 using the new keyword to build it on the heap.

bitset::bitset(int n_bits){
    if (n_bits % 64 !=0) size (n_bits / 64) + 1;
    else size = n_bits / 64;
    this->data = new uint64[size];
}

Doing do allows my program to consistently allows my whole program to access the array of bits. The One issue I'm running into is that my destructor doesn't seem to be able to delete the data

bitset::~bitset(){
    delete[] this->data;
}

Working without the destructor, I get a memory leak (as expected), with the destructor I get a runtime error Error in `./a.out': double free or corruption (out): I have tried googling this to no avail. I am fairly new to c++, so any insight on stack/heap behavior within classes would be appreciated.

elitk19
  • 31
  • 4
  • Your class failed to implement a user-defined copy constructor and assignment operator. The fix was given by the answer (use `std::vector`), but if you really need to know what to do to fix the error without introducing vector, the rule of 3 explains it. Look at the **Managing Resources** section at the link. – PaulMcKenzie May 13 '19 at 00:14
  • I'll look into this, Since this is good practice I will implement the copy constructor, but hypothetically speaking, if I simply passed the bitset object by reference for its whole lifespan, would I avoid the double free? From my understanding passing by reference doesn't make a copy. – elitk19 May 13 '19 at 00:25
  • The issue with what you mentioned is that copying can occur in places that you haven't checked or may have forgotten. To alleviate that, then you should let the compiler tell you where you're making copies, and that can be done by making the functions `deleted`, i.e. `bitset(const bitset&) = delete;` and `bitset& operator=(const bitset&) = delete;`. But truthfully, you should make your class copyable. It makes more sense (to me) to be able to place `bitset` in a container that uses value semantics. Also, you should put `bitset` in its own namespace, as there is a `std::bitset` class in C++ – PaulMcKenzie May 13 '19 at 00:28

1 Answers1

1

You can use the vector container:

class bitset{
    ...
    std::vector<uint64> bits;
    ...

Vector takes care of memory allocation so that you don't get problems with accidentally deleting memory more than once or accidentally leaking the memory.


P.S. unsigned long long is not guaranteed to be exactly 64 bits. It is allowed to be bigger than that. If that is crucial detail to your program, then you should use std::uint64_t from the standard library instead. This is mostly only relevant to future compatibility.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • I'll give that a try. The one way I see a potential problem is that I will need to send this bitset over a socket. I'm assuming ```std::vector``` has all the same access operators overloaded as an array? – elitk19 May 13 '19 at 00:02
  • @EliKolb Vector is simply a container that contains a dynamically allocated array. The `data` member function gives you a pointer to the first element which you can use exactly like you would use any other pointer to an element of an array (except you don't need to, nor can you take ownership of the pointer). – eerorika May 13 '19 at 00:05