如果我有一个如此定义的类:
class classWithInt
{
public:
classWithInt();
...
private:
int someInt;
...
}
并且someInt
是classWithInt
中唯一的一个成员变量,声明这个类的新实例比仅声明一个新整数要慢多少?
你有什么时候,在班上说10个这样的整数? 100?
答案 0 :(得分:41)
编译器不是在凌晨时分由醉酒的大学生写的,开销是零。至少在你开始使用virtual
函数之前;那么你必须支付虚拟调度机制的费用。或者如果类中有 no 数据,在这种情况下,类仍然需要占用一些空间(这又是因为每个对象在内存中必须有唯一的地址)。
函数不是对象数据布局的一部分。它们只是对象心理概念的一部分。该函数被转换为代码,该代码将对象的实例作为附加参数,并且对成员函数的调用被相应地转换为传递对象。
数据成员的数量无关紧要。比较苹果和苹果;如果你有一个10个整数的类,那么它占用10个整数的相同空间。
无论它们是什么,在堆栈上分配东西都是免费的。编译器将所有局部变量的大小相加,并一次调整堆栈指针以为它们腾出空间。在内存成本中分配空间,但成本可能更多地取决于分配数量而不是分配的空间量。
答案 1 :(得分:7)
好吧,让我们全力以赴。我可以通过完全优化来编译一个更完整的例子,如下所示:
void use(int &);
class classWithInt
{
public:
classWithInt() : someInt(){}
int someInt;
};
class podWithInt
{
public:
int someInt;
};
int main() {
int foo;
classWithInt bar;
podWithInt baz;
use(foo);
use(bar.someInt);
use(baz.someInt);
return 5;
}
这是我从gcc-llvm
获得的输出; ModuleID = '/tmp/webcompile/_21792_0.bc'
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-linux-gnu"
%struct.classWithInt = type { i32 }
define i32 @main() {
entry:
%foo = alloca i32, align 4 ; <i32*> [#uses=1]
%bar = alloca %struct.classWithInt, align 8 ; <%struct.classWithInt*> [#uses=1]
%baz = alloca %struct.classWithInt, align 8 ; <%struct.classWithInt*> [#uses=1]
%0 = getelementptr inbounds %struct.classWithInt* %bar, i64 0, i32 0 ; <i32*> [#uses=2]
store i32 0, i32* %0, align 8
call void @_Z3useRi(i32* %foo)
call void @_Z3useRi(i32* %0)
%1 = getelementptr inbounds %struct.classWithInt* %baz, i64 0, i32 0 ; <i32*> [#uses=1]
call void @_Z3useRi(i32* %1)
ret i32 5
}
declare void @_Z3useRi(i32*)
每种情况都有一些差异。在最简单的情况下,POD type与plain int的区别仅在于一种方式,它需要不同的对齐,它是8字节对齐而不是仅仅4字节。
另一个值得注意的事情是POD和裸int没有被初始化。它们的存储空间正好从堆栈的荒野中使用。非pod类型具有非平凡的构造函数,在实例可用于其他任何内容之前会导致存储零。