Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What determines max_size in STL containers?

Tags:

c++

I'm trying to reproduce the behavior of std::string in C, but there is one thing I don't really know how to do. There is a max_size member method that gives the maximum size a string (or any other arrays for vector, etc...) can have, so my question is I know this value can depend of systems, so how do containers determine this number ? And could I get it in C?

like image 231
Fayeure Avatar asked Apr 21 '21 12:04

Fayeure


People also ask

What is Max_size?

The set::max_size() is a built-in function in C++ STL which returns the maximum number of elements a set container can hold. Syntax: set_name.max_size() Parameters: This function does not accept any parameters. Return Value: This function returns the maximum number of elements a set container can hold.

Are STL containers passed by reference?

@BjörnPollex Yes! I forgot to mention that.

What is maximum vector length?

max_size() is the theoretical maximum number of items that could be put in your vector. On a 32-bit system, you could in theory allocate 4Gb == 2^32 which is 2^32 char values, 2^30 int values or 2^29 double values.

What is max_size() function in C++ STL?

The set::max_size () is a built-in function in C++ STL which returns the maximum number of elements a set container can hold. Parameters: This function does not accept any parameters. Return Value: This function returns the maximum number of elements a set container can hold. Below program illustrates the above funnction:

What is containers in C++ STL?

Containers in C++ STL (Standard Template Library) Last Updated: 12-07-2020 A container is a holder object that stores a collection of other objects (its elements).

How to find the maximum element in a container for range?

If we use std::max () to find the maximum element in a container for a range, then we have to write our own iterator and comparator. std::max_element () is pretty handy if we would want to find the maximum element value in a subrange.

What is the size of a container?

The size of a container is the number of elements it contains. Or said differently, the number of elements passed over in an iteration from beginning to end. This is an information which is fundamentally part of the container interface.


Video Answer


2 Answers

What determines max_size in STL containers?

The implementer of the standard library chooses it. The implementers should design containers to support as large sizes as possible, given the limitations imposed by the API and the target system. The implementation defails of the container, and the supplied allocator may impose additional limitations that should ideally be reflected by a lowered (and thus more accurate) max_size.

Note that max_size is only rarely useful value in practice. It is a theoretical upper bound that is not necessarily practically reachable... typically because memory isn't sufficient, at least on 64 bit systems. It's used to detect obviously erroneus user input early (and then throw exception accordingly).

And could I get it in C?

You can define a constant extern variable and initialise it in a c++ translation unit. Example:

// common_header.h
// add header guard here
#include <stdlib.h>

#ifdef __cplusplus
extern "C" {
#endif

extern const size_t cpp_string_max_size;
extern const size_t cpp_vector_int_max_size;

#ifdef __cplusplus
}
#endif

// source.cpp
#include "common_header.h"
#include <string>
#include <cstdlib>
#include <vector>

const std::size_t cpp_string_max_size = std::string{}.max_size();
const std::size_t cpp_vector_int_max_size = std::vector<int>{}.max_size();

Then, compile the C++ translation unit using a C++ compiler and link it with the C program.


I'm searching for a way that doesn't involve any C++

Depending on what you mean by "any C++", you can use meta-programming: Write a C++ program that produces a C source file that contains constants that were produced by the C++ program. The generation part obviously involves C++, but the generated source will be pure C and can be compiled using only a C compiler.

If this isn't to your liking, you can go read the implementation files of your chosen C++ standard library and see how they have implemented max_size, and write the C source manually. This doesn't involve writing or compiling any C++ at any point, although it does involve reading C++.

like image 105
eerorika Avatar answered Oct 23 '22 13:10

eerorika


max_size defines the maximum size a container theoretically can have for the particular implementation of that container.

That number does not depend on the OS or the available memory but is only given by the implementation of the container.

If your (not std::string compatible) implementation of a string container is like this:

struct string {
   unsigned char size;
   char *data;

   // … further functions …
};

Then max_size would likely refer to the largest number unsigned char can represent.

If your implementation is just a \0 terminated string, without any other meta information. Then max_size might refer to the maximum number of bytes that can be addressed through pointers, for the given target architecture.

So max_size just says, the way the container is implemented would be able to handle max_size number of elements. But it does not guarantee that the OS is capable of that.


For an std::string the upper bounds of the maximum number of chars the implementation can handle is given by a maximum number of size_type and some further constraints.

The size_type for a std::string itself is given by the used allocator (std::allocator<CharT>) which defaults to std::allocator_traits<Allocator>::size_type.

For a std::allocator the size_type referees to std::size_t.

So for a std::string the upper bound of max_size is the max value of std::size_t minus a value n that is required to fulfill the other requirements of the string.

The libstdc++ of gcc-4.6.2 defines says this about the max_size:

// The maximum number of individual char_type elements of an
// individual string is determined by _S_max_size. This is the
// value that will be returned by max_size().  (Whereas npos
// is the maximum number of bytes the allocator can allocate.)
// If one was to divvy up the theoretical largest size string,
// with a terminating character and m _CharT elements, it'd
// look like this:
// npos = sizeof(_Rep) + (m * sizeof(_CharT)) + sizeof(_CharT)
// Solving for m:
// m = ((npos - sizeof(_Rep))/sizeof(CharT)) - 1
// In addition, this implementation quarters this amount.
static const size_type  _S_max_size;
static const _CharT _S_terminal;

and that corresponding initialization

template<typename _CharT, typename _Traits, typename _Alloc>
  const typename basic_string<_CharT, _Traits, _Alloc>::size_type
  basic_string<_CharT, _Traits, _Alloc>::
  _Rep::_S_max_size = (((npos - sizeof(_Rep_base))/sizeof(_CharT)) - 1) / 4;

According to this 197. max_size() underspecified (not sure if there is any newer update to that), the value of max_size won't change from call to call:

It is clear to the LWG that the value returned by max_size() can't change from call to call.

So you can use the approach of eerorika to get that value for a specific allocator.

like image 27
t.niese Avatar answered Oct 23 '22 13:10

t.niese