How can I get sizeof a vector::value_type?

2020-02-09 07:09发布

问题:

I want to get sizeof of the type that is contained in a vector. Here is what I tried:

#include <iostream>
#include <vector>

int main()
{
    std::vector<uint> vecs;
    std::cout << sizeof(vecs.value_type) << std::endl;
    return 0;
}

From my understanding this should be correct. However, when compiling with GCC 4.8.1 this is what I get:

test-sizeof.cpp: In function ‘int main()’:
test-sizeof.cpp:7:27: error: invalid use of ‘std::vector<unsigned int>::value_type’
  std::cout << sizeof(vecs.value_type) << std::endl;
                           ^

What am I doing wrong? How can I get the size of the contained type?

回答1:

3.4.3 Qualified name lookup [basic.lookup.qual]

1 The name of a class or namespace member or enumerator can be referred to after the :: scope resolution operator (5.1) applied to a nested-name-specifier that denotes its class, namespace, or enumeration. If a :: scope resolution operator in a nested-name-specifier is not preceded by a decltype-specifier, lookup of the name preceding that :: considers only namespaces, types, and templates whose specializations are types. If the name found does not designate a namespace or a class, enumeration, or dependent type, the program is ill-formed.

In this case, you are accessing a type member from the class template specialization std::vector<uint>, and you need to do it by writing:

std::vector<uint>::value_type

In case you are actually inside templated code and want to e.g. access the same nested type, you need to prefix it with the keyword typename like this:

typename std::vector<T>::value_type

In C++11, you can use sizeof(decltype(vecs)::value_type) or also sizeof(decltype(vecs.back())), the latter is convenient if you don't know the precise name of the type but know how to access them through a member function like back().

Note: as pointed out by @Casey in the comments, decltype requires stripping references in order to get the type itself, but for sizeof purposes that doesn't matter.



回答2:

The member access operator . can only be used to access data members and member functions of classes, not other nested names such as type names. You'll need the scope resolution operator :: to access them, and that can only be applied to the class name (or an alias), not an object of class type:

std::vector<uint>::value_type

In C++11 or later, decltype can give you a type name, if you have an object and no convenient access to the type:

decltype(vecs)::value_type


回答3:

The comments pretty much said it all: if you know the type of the vector, you can use sizeof(std::vector<uint>::value_type). Otherwise use sizeof(decltype(vecs)::value_type).

decltype is a magical C++11 construct that evaluates to the type of its argument, so the code

int i;
float f;

decltype(i) j;
decltype(f) g;

Is the same as

int i;
float f;

int j;
float g;

Only use the . operator for fields and methods (technically it can be used for static variable as well, but it's considered bad practice). For anything else, such as static variables, inner classes, or class-scope template parameters or typedefs (such as value_type), use the scope-resolution operator ::.



回答4:

I prefer the more concise:

sizeof(vecs[0])

Which at first glance seems unsafe because what happens when vecs is a zero length vector?

For this example where the argument to sizeof() operator is called on a value type, the sizeof() operator is executed at compile time and so vecs[0] can never cause a segfault or crash.

p.s. sizeof() is only evaluated at runtime when the argument is a variable-length-array (from C or GNU C++ extension)