The golden C++ "as-if" rule1 states that, if the observable behavior http://eel.is/c++draft/intro.abstract#def:behavior,observable of a program doesn't depend on an unused data-member existence, the compiler is allowed to optimized it away.
未使用的成员变量是否占用内存?
否(如果“确实”未使用过)。
现在想到两个问题:
- 什么时候可观察的行为不依赖于成员的存在?
- 现实生活中的节目中会出现这种情况吗?
让我们从一个例子开始。
Example
#include <iostream>
struct Foo1
{ int var1 = 5; Foo1() { std::cout << var1; } };
struct Foo2
{ int var1 = 5; int var2; Foo2() { std::cout << var1; } };
void f1() { (void) Foo1{}; }
void f2() { (void) Foo2{}; }
如果我们问gcc 编译这个翻译单元 https://godbolt.org/z/Uc3biG,它输出:
f1():
mov esi, 5
mov edi, OFFSET FLAT:_ZSt4cout
jmp std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
f2():
jmp f1()
f2
是相同的f1
,并且没有内存被用来保存实际的Foo2::var2
. (Clang 做了类似的事情 https://godbolt.org/z/12AD9W).
讨论
有些人可能会说这是不同的,原因有两个:
- 这是一个太微不足道的例子,
- 该结构已完全优化,它不算数。
嗯,一个好的程序是简单事物的智能而复杂的组装,而不是复杂事物的简单并置。在现实生活中,您使用简单的结构编写大量简单的函数,而不是编译器优化掉的。例如:
bool insert(std::set<int>& set, int value)
{
return set.insert(value).second;
}
这是数据成员的真实示例(此处,std::pair<std::set<int>::iterator, bool>::first
) 未使用。你猜怎么了?它被优化掉了 https://godbolt.org/z/ALIUIk (带有虚拟集的更简单示例 https://godbolt.org/z/-CJtZd如果那个集会让你哭泣)。
现在是最佳时机阅读 Max Langhof 的精彩回答 https://stackoverflow.com/a/55061163/5470596(请为我投票)。它最终解释了为什么结构的概念在编译器输出的汇编级别没有意义。
“但是,如果我做 X,未使用的成员被优化掉的事实就是一个问题!”
有许多评论认为这个答案一定是错误的,因为某些操作(例如assert(sizeof(Foo2) == 2*sizeof(int))
)会破坏一些东西。
If X is part of the observable behavior of the program2, the compiler is not allowed to optimized things away. There are a lot of operations on an object containing an "unused" data-member which would have an observable effect on the program. If such an operation is performed or if the compiler cannot prove none is performed, that "unused" data-member is part of the observable behavior of the program and cannot be optimized away.
影响可观察行为的操作包括但不限于:
- 获取某种类型对象的大小(
sizeof(Foo)
),
- 获取在“未使用”的数据成员之后声明的数据成员的地址,
- 使用类似的函数复制对象
memcpy
,
- 操纵对象的表示(就像
memcmp
),
- 将对象限定为volatile,
-
etc.
1)
[intro.abstract]/1 http://eel.is/c++draft/intro.abstract#1
本文档中的语义描述定义了参数化的非确定性抽象机。本文档对一致性实现的结构没有提出要求。特别是,它们不需要复制或模拟抽象机的结构。相反,需要一致的实现来模拟(仅)抽象机的可观察行为,如下所述。
2) Like an assert passing or failing is.