Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Define struct with minimum size

Tags:

c++

struct

I want to define a struct, e.g. type, such that sizeof(type) is no less than some value.

Motivation:

I have a vector std::vector<type> and I will remove some elements from it. Also, I have saved the indexes of some elements to other places, thus I want just mark it as not used and reuse it in the future. This leads me to save the next available position as a list in erased positions. As a result, sizeof(type) should be no less than sizeof(size_t) and type should be properly aligned as well.

Possible Solutions:

  1. boost::variant<type, size_t>

    This has two problems from my point of view. If I use boost::get<type>, the performance will decrease significantly. If I use boost::apply_visitor, the syntax would be weird and the performance also decreases according to my profile.

  2. union{type t; size_t s;}

    This of course works except for two shortfalls. Firstly, the syntax to refer the member of type would be more messy. Secondly, I have to define constructor, copy constructor, etc. for this union.

  3. Extend type by char[sizeof(size_t) - sizeof(type)]

    This almost fulfills my requirements. However, this risks of zero length array which is not supported by the c++ standard and possibly wrong alignment.

Since I won't use type as size_t often, I'd like to just ensure I can use reinterpret_cast<size_t> when needed.

Complements

After reading the comments, I think the best solution for my problem should be boost::variant. But I am still wondering is there a way to combine the benefits of solution 2 and 3, i.e.

a. I can access members of type without changes.

b. Get the guarantee that reinterpret_cast<size_t> works.

like image 304
cqdjyy01234 Avatar asked Jan 10 '15 07:01

cqdjyy01234


People also ask

What is minimum size of structure in C?

The minimum size must be one byte.

Can you use sizeof on a struct?

The sizeof for a struct is not always equal to the sum of sizeof of each individual member. This is because of the padding added by the compiler to avoid alignment issues. Padding is only added when a structure member is followed by a member with a larger size or at the end of the structure.

How do you define the size of a structure?

In 32 bit processor, it can access 4 bytes at a time which means word size is 4 bytes. Similarly in a 64 bit processor, it can access 8 bytes at a time which means word size is 8 bytes. Structure padding is used to save number of CPU cycles. Let's see what compiler is giving using the sizeof() operator.

What is struct size in C?

The size of the entire structure is 8 bytes. On knowing the structured padding, it is easier to redesign or rewrite the structure.


2 Answers

You can mitigate the concerns about solution 3 with something like:

struct data
{
  // ...
};

template<class T, bool> class pad_;
template<class T> class pad_<T, true> { char dummy[sizeof(T) - sizeof(data)]; };
template<class T> class pad_<T, false> {};

template<class T> using pad = pad_<T, (sizeof(T) > sizeof(data))>;

class type : public data, pad<size_t>
{
  // ...
};

This code:

  • assumes empty base optimization so that pad could be completely optimized out from type layout when sizeof(data) >= sizeof(size_t)
  • hasn't the risk of zero length array
like image 171
manlio Avatar answered Sep 27 '22 16:09

manlio


Though this being an interesting problem the design itself seams questionable.

  1. When inserting a new element items marked unused are considered first before growing the vector. It means that the relative order of items is unpredictable. If that's being acceptable you could have just used a vector of (smart) pointers.

    Typically a vector is inefficient when removing items from the middle. Since the order doesn't matter it is possible to swap the element being removed with the last element and pop the last element.

  2. All elements are of the same size; allocating them using a pool could be faster then using the system allocator.

    A pool basically allocates memory in big chunks and hands out smaller chunks on request. A pool usually stores the free list in yet unallocated chunks to track available memory (the same very idea described in the question). There are some good implementations readily available (from Boost and other sources).

  3. Concerning the original design it is cumbersome to enumerate elements in the vector since real elements are mixed with "holes", the logic is going to be obfuscated with additional checks.

Probably there is some sold reasoning behind the original design; unfortunately @user1535111 is not telling the details.

like image 33
Nick Zavaritsky Avatar answered Sep 27 '22 16:09

Nick Zavaritsky