2010-12-04 3 views
16

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

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

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

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

+9

Занятия - дьявол. Вы никогда не должны их использовать. Весь ваш код должен быть в одном огромном модуле с множеством функций и должен использовать простые типы в глобальных переменных. По соответствующей заметке; Я должен прекратить посещать этот сайт, чувствуя себя особенно саркастическим. : p – 2010-12-04 06:19:16

+0

Почему бы не попробовать создать 100 классов и 100 ints? или даже миллион ints! – PostMan 2010-12-04 06:20:12

+0

Вы пробовали его и профилировали? Почему это имеет значение? Зачем вам это делать? Готов поспорить, что это в сотни раз медленнее, но ваш компилятор МОЖЕТ быть в состоянии сделать некоторые причудливые вещи. Какой прецедент у вас есть, что делает это актуальным? – Falmarri 2010-12-04 06:21:20

ответ

37

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

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

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

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

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 отличается от простого int только одним способом, для него требуется другое выравнивание, оно равно 8 байтам, а не только 4 байта.

Другое примечательное, что POD и bare int не инициализируются. Их хранилище используется так же, как и в пустыне стека. Тип non-pod, который имеет нетривиальный конструктор, заставляет ноль хранить до того, как экземпляр можно использовать для чего-либо еще.

Смежные вопросы