创建新类的开销

时间:2010-12-04 06:12:04

标签: c++ class optimization int

如果我有一个如此定义的类:

class classWithInt
{
public:
    classWithInt();
...
private:
    int someInt;
...
}

并且someIntclassWithInt中唯一的一个成员变量,声明这个类的新实例比仅声明一个新整数要慢多少?

你有什么时候,在班上说10个这样的整数? 100?

2 个答案:

答案 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类型具有非平凡的构造函数,在实例可用于其他任何内容之前会导致存储零。