创建新类的开销

发布于 2024-10-06 04:05:10 字数 262 浏览 5 评论 0原文

如果我有一个这样定义的类:

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

并且 someIntclassWithInt 中唯一的一个成员变量,那么声明该类的新实例会慢多少类而不是仅仅声明一个新整数?

如果类中有 10 个这样的整数呢? 100?

If I have a class defined as such:

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

and that someInt is the one and only one member variable in classWithInt, how much slower would it be to declare a new instance of this class than to just declare a new integer?

What about when you have, say 10 such integers in the class? 100?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

乜一 2024-10-13 04:05:10

使用不是由喝醉的大学生在凌晨编写的编译器,开销为零。至少在您开始放入虚拟函数之前;那么你必须支付虚拟调度机制的费用。或者,如果类中没有数据,在这种情况下,类仍然需要占用一些空间(这又是因为每个对象在内存中必须有唯一的地址)。

函数不是对象数据布局的一部分。它们只是对象心理概念的一部分。该函数被翻译成将对象实例作为附加参数的代码,并且对成员函数的调用也相应地被翻译为传递该对象。

数据成员的数量并不重要。将苹果与苹果进行比较;如果你有一个包含 10 个整数的类,那么它所占用的空间与 10 个整数所占用的空间相同。

在堆栈上分配东西实际上是免费的,无论它们是什么。编译器将所有局部变量的大小相加,并立即调整堆栈指针以为它们腾出空间。分配内存空间会产生成本,但成本可能更多地取决于分配数量,而不是分配的空间量。

With a compiler not written by drunk college students in the wee hours of the morning, the overhead is zero. At least until you start putting in virtual functions; then you must pay the cost for the virtual dispatch mechanism. Or if you have no data in the class, in which case the class is still required to take up some space (which in turn is because every object must have a unique address in memory).

Functions are not part of the data layout of the object. They are only a part of the mental concept of the object. The function is translated into code that takes an instance of the object as an additional parameter, and calls to the member function are correspondingly translated to pass the object.

The number of data members doesn't matter. Compare apples to apples; if you have a class with 10 ints in it, then it takes up the same space that 10 ints would.

Allocating things on the stack is effectively free, no matter what they are. The compiler adds up the size of all the local variables and adjusts the stack pointer all at once to make space for them. Allocating space in memory costs, but the cost will probably depend more on the number of allocations than the amount of space allocated.

本王不退位尔等都是臣 2024-10-13 04:05:10

好吧,让我们测试一下。我可以通过全面优化来编译一个更完整的示例,如下所示:

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 类型 与普通 int 的区别仅在于一个方面,它需要不同的对齐方式,它是 8 字节对齐而不是 4 字节对齐。

另一个值得注意的事情是 POD 和 bare int 没有被初始化。它们的存储就像来自堆栈的荒野一样使用。非 Pod 类型具有重要的构造函数,会导致在实例用于其他任何操作之前存储零。

well, lets just test it all out. I can compile, with full optimizations, a more complete example like so:

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;

}

And this is the output I get from 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*)

There are some differences in each case. In the simplest case, the POD type differs from the plain int in only one way, it requires a different alignment, it's 8 byte aligned instead of just 4 byte.

The other noticeable thing is that the POD and bare int do not get initialized. Their storage is used right as is in from the wilderness of the stack. The non-pod type, which has a non-trivial constructor, causes a zero to be stored before the instance can be used for anything else.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文