Подтвердить что ты не робот

Накладные расходы на создание нового класса

Если у меня есть класс, определенный как таковой:

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

и что someInt является единственной и единственной переменной-членом в classWithInt, насколько медленнее было бы объявлять новый экземпляр этого класса, чем просто объявить новое целое число?

Как насчет того, когда у вас есть, скажите 10 таких целых чисел в классе? 100?

4b9b3361

Ответ 1

С компилятором, не написанным пьяными студентами в утренние часы утра, накладные расходы равны нулю. По крайней мере, пока вы не начнете вводить функции virtual; то вы должны оплатить стоимость виртуального механизма отправки. Или, если у вас есть нет данные в классе, и в этом случае класс по-прежнему должен занимать некоторое пространство (что, в свою очередь, связано с тем, что каждый объект должен иметь уникальный адрес в памяти).

Функции не являются частью макета данных объекта. Они являются лишь частью ментальной концепции объекта. Функция преобразуется в код, который принимает экземпляр объекта в качестве дополнительного параметра, а вызовы функции-члена соответственно переводится для передачи объекта.

Число членов данных не имеет значения. Сравните яблоки с яблоками; если у вас есть класс с 10 int в нем, тогда он занимает то же место, что и 10 ints.

Выделение вещей в стеке эффективно бесплатно, независимо от того, что они собой представляют. Компилятор добавляет размер всех локальных переменных и одновременно настраивает указатель стека, чтобы освободить место для них. Выделение пространства в памяти стоит, но стоимость, вероятно, будет больше зависеть от количества распределений, чем объем выделенного пространства.

Ответ 2

Хорошо, давайте просто протестируем все это. Я могу скомпилировать с полной оптимизацией более полный пример:

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*)

В каждом случае есть некоторые различия. В простейшем случае тип