Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I tell the size of an array created with "new type[n]" in C++?

Tags:

c++

c++11

Using C++11, I like to create an array of booleans and immediately clear it

bool *mymap = new bool[n];

n is variable.

Now, does this already clear the memory occupied by the array? If not, is there a better approach to clear the array than using a loop over all elements, setting each to false individually?

I considered using std:memset(), but that requires me to know the size of the array. Now, beginners might say: Easy, the size is n*sizeof(bool). But I don't buy that. The compiler might decide to pack them differently, even pack them as bits, couldn't it?

So, is there a way to tell the size of the array more cleanly? I imagine there might be a std:arraysize() function that simply returns the space of the allocated array in memory. After all, that information must be maintained at runtime somehow, or a delete invocation wouldn't know how much to release, right?

like image 719
Thomas Tempelmann Avatar asked Aug 14 '13 10:08

Thomas Tempelmann


People also ask

Does C store array size?

C does not store the size of the array - period. That is a fact of life. And, when an array is passed to a function, the size information is not passed to the function; the array 'decays' to a pointer to the zeroth element of the array - and only that pointer is passed.

How does free () know the size of memory to be allocated?

How does free() know the size of memory to be deallocated? The free() function is used to deallocate memory while it is allocated using malloc(), calloc() and realloc(). The syntax of the free is simple. We simply use free with the pointer.

Can array size be changed in C?

Arrays are static so you won't be able to change it's size. You'll need to create the linked list data structure.


7 Answers

The answer to the specific question is no, you cannot determine the length of the array pointed at by mymap. The language simply provides no mechanism for that.

But if all you want to do is make sure that all the elements of the array are set to false, then all you have to do is value initialize it:

bool* mymap = new bool[n]();
//                       ^^

Unfortunately, this only works for zero-like values for built-in types. There would be no equivalent way to set all the values to true.

like image 78
juanchopanza Avatar answered Oct 03 '22 17:10

juanchopanza


You cannot do it in a standard way. However, different compilers support different hacks to do it, for example:

#if defined(_MSC_VER) || ( defined(__GNUC__) && defined(_WIN32) )
      // a dirty MSVC and MinGW hack
      size_t Size = _msize( mymap );
#elif defined(__GNUC__)
      // a dirty glibc hack  
      size_t Size = malloc_usable_size( mymap );
#else
   #error Implement for any other compiler
#endif      

But these are real hacks, so beware.

By the way, std::vector can help you to solve your problem within the standard.

like image 33
Sergey K. Avatar answered Oct 03 '22 17:10

Sergey K.


No you can't, because it's not actually an array. mymap is just a normal pointer to some heap memory, and if you need to know the size you either have to keep track of it yourself or use a standard container such as std::vector.

Oh, and if you want a more generic variant of memset read about std::fill.

like image 40
Some programmer dude Avatar answered Oct 03 '22 17:10

Some programmer dude


No, the compiler can't decide to pack them except so that the size of the region is n * sizeof(bool) - doing it any other way would break the ability to address individual array members as mymap[x] (which is the same as *(mymap + x)).

In this case, beginners' suggestion is the correct one.

like image 22
user4815162342 Avatar answered Oct 03 '22 15:10

user4815162342


You can try this:

bool *mymap = new bool[n] ();

However this sets to false and you cannot use such a way to set to true.

like image 25
ST3 Avatar answered Oct 03 '22 15:10

ST3


Let's assume that the compiler decides to pack differently.

Assumption 1: the compiler packs some bits together into one byte. If you take the address of a single element inside the array, it's of type bool. Since the compiler can not (in general) deduct what you will do with this address (e.g. passing it to a function which passes it to a lib, ...), bit-packing inside one byte can't really happen. Otherwise the compiler needs to mask the appropriate bit from its packed region and move it somewhere as a real bool.

Assumption 2: the compiler uses more than sizeof(bool) for one bool value. Highly unlikely - because then sizeof(bool) would simply be greater. Pointer-manipulations are still possible and in case of bit-arrays some other magic logic needs to be implemented.

Assumption 3: the compiler uses different sizes for the different fields of the array - even more unlikely. The administration information required is just too big.

From these 3 thoughts I'd say the simple solution is the best. Just to be sure for now and all the future of your program, write a small unit-test that tests exactly that (e.g. get the address of the first value, cast it to a pointer of a type that has the same sizeof as bool, calculate the address of element n, cast that address back to a pointer of bool, write something there and compare with the array access). Then you'll get a notification if something changes - but I doubt it will.


Sidenote - of course the compiler is always able to allocate more memory than required. But still, the array has that size (it's just placed in a larger chunk of memory).

like image 41
Tobias Langner Avatar answered Oct 03 '22 15:10

Tobias Langner


In bare bone C++, no it is not possible. However you are encouraged (and really should) consider using a class to manage the memory anyway.

In C++98, you can either use a boost::scoped_array or a std::vector (though for bool you might prefer a std::vector<char>).

In C++11, you should consider replacing boost::scoped_array by std::unique_ptr<bool[]>.

The issue is until then, apart from std::vector, none of those know the size of the array they contain; they just handle memory.

In C++14, a new contender appear: std::dynarray. It's a trimmed down version of std::vector whose size cannot be resized dynamically. In short, exactly what you want: just the array and its length, no overhead.

If your favorite compiler/toolchain does not support dynarray yet you can easily implement it yourself:

template <typename T>
class dynarray {
public:
    // methods go here.
private:
    size_t size;
    std::unique_ptr<T[]> array;
}; // class dyn_array
like image 23
Matthieu M. Avatar answered Oct 03 '22 15:10

Matthieu M.