C++标准库上的sizeof()
sizeof() on C++ Standard Library
我很好奇,在一些C++标准库类上应用了sizeof()
运算符。以下是我观察到的:
int main()
{
vector<double> v1;
set<double> s1;
map<double,double> m1;
stack<char> st;
queue<char> q;
vector<char> v2;
set<char> s2;
map<char,char> m2;
cout<<sizeof(v1)<<" "<<sizeof(s1)<<" "<<sizeof(m1)<<endl;
cout<<sizeof(v2)<<" "<<sizeof(s2)<<" "<<sizeof(m2)<<endl;
cout<<sizeof(q)<<" "<<sizeof(st)<<endl;
return 0;
}
我的系统(64位)的输出是:
12 24 24
12 24 24
40 40
我知道std::set
使用红黑树来实现。因此,二进制树的每个节点都有两个指针(每个指针8个字节),并且值(8个字节,总共24个)看起来不错。
std::map
(也使用红黑树)有一个额外的密钥,但仍然是24字节?为什么?为什么
std::queue
和std::stack
占用40个字节,而std::vector
只占用12个字节?为什么
char
和double
不影响类的大小?是因为模板吗?
这些类的实现是一个黑盒,无法判断它们包含哪些数据或私有成员。这完全取决于实施。
了解对象实例中所有字节的唯一方法是读取源代码。
sizeof
运算符将为您提供类型的大小。
现在,如果我在这里制作一个非常简化的std::vector<T>
版本(请注意,这并不像真正的实现那样做任何事情,而且它太简化了,无法真正工作——我跳过了实际实现中真正需要的很多部分):
template<typename T>
class vector<T>
{
public:
typedef size_t size_type;
private:
T* mdata;
size_type msize;
size_type mreserved;
public:
vector() { mreserved = msize = 0; mdata = 0; }
vector(size_type sz) { msize = 0; mreserved = sz; mdata = new T[sz](); }
void push_back(const T& v)
{
if (msize + 1 > mreserved) grow(mreserved * 2);
mdata[msize+1] = v;
msize++;
}
size_type size() const { return msize; }
// bunch of other public functions go here.
private:
void grow(size_type newsize)
{
if (newsize < 8) newsize = 8;
T* newdata = new T[newsize];
for(size_type i = 0; i < msize; i++) newdata[i] = mdata[i];
swap(mdata, newdata);
delete [] mdata;
mreserved = newsize;
}
};
正如您所看到的,无论存储的数据集有多大,实际类的大小都是相同的(它包含相同大小和数量的元素)。换句话说,sizeof(vector<int>)
是恒定的。存储在mdata
后面的数据的大小当然在变化,但sizeof
不知道(不知道)。
此示例源代码将为您提供以下想法:
struct A
{
int* p; //4 bytes
A(int n)
{
p = new int[n];
}
};
int main()
{
A x1(10);
A x2(100);
cout << boolalpha << (sizeof(x1) == sizeof(x2)); //prints true
}
原因是A只包含一个指针。指针的大小始终相同(通常为4)。指针指向什么并不重要——1000或1000000的动态数组。现在还是4点。
Char或double不影响大小,因为指向Char的指针与指向double的指针大小相同。
对于一个std::数组,它实际上包含一个数组,而不是指针,这些都很重要(数组类型和大小):
cout << boolalpha << ((sizeof(std::array<int, 10>) == sizeof(std::array<int, 11>)); //false!
cout << boolalpha << ((sizeof(std::array<int, 10>) == sizeof(std::array<long double, 10>)); //false!
重要的是要记住,sizeof
是在编译时求值的:因此它在任何意义上都不是动态的。
它的工作是返回类/结构/普通旧数据的大小;没有别的。
这就是为什么它总是为向量、集合和贴图提供相同的结果。
您似乎假设容器类的大小可以随着所消耗元素的数量而增加,但这在物理上是不可能的,因为所有类型都有固定的大小。
相反,元素是使用动态分配间接存储的sizeof
不会向您透露此信息。
sizeof
提供的唯一信息是在容器的构建和管理中使用了多少指针、计数器、标志和其他元数据;这种细节是从你身上抽象出来的,你永远不应该试图对其进行合理化。
- 使用CMake检测支持的C++标准
- 如何理解C++标准N3337中的expr.const.cast子句8
- "throw expression code" 1e7 >返回 d 是什么?投掷标准::overflow_error( "too big" ) : d;意味 着?
- 编译标准库类型
- 标准是否使用多余的大括号(例如 T{{{10}}})定义列表初始化?
- 编译器如何在使用SFINAE的函数和标准函数之间确定两者是否可行
- 铸造标准::有没有回到原来的类型
- 标准 N3337 5.2.10 第 7 条中的C++"类型"是什么意思?
- this_thread::sleep_for和计时时钟之间的关系是否由C++11标准指定
- 标准库类型的赋值运算符的引用限定符
- 标准是否严格定义了该程序应该如何编译?
- 如何从Windows应用程序输出到标准?
- 安全到标准:移动会员?
- 如何正确将字符串转换为标准::时间::system_clock::time_point?
- 这是否符合C++标准:双响双响,例如!!(-0.0).
- 标准::变体的赋值运算符
- C 标准中的哪个段落验证了以下示例中使用的表达式`sizeof(s :: m 42)`
- C++标准库上的sizeof()
- 标准是否保证std::向量占用的总内存按C+N*sizeof(T)缩放
- 获得sizeof(提升(x))的标准方法