Похоже, ваш вопрос просто: В чем разница между вызовом «ptr-> что-то() "и" instance.something()? "
С точки зрения функции «что-то», абсолютно ничего.
#include <iostream>
struct Foo {
void Bar(int i) { std::cout << i << "\n"; }
};
int main() {
Foo concrete;
Foo* dynamic = new Foo;
concrete.Bar(1);
dynamic->Bar(2);
delete dynamic;
}
Компилятор излучает только один экземпляр Foo :: Bar(), который должен обрабатывать оба случая, так что не может быть какая-то разница.
Только изменения, если они есть, находятся на сайте вызова. При вызове dynamic->Bar()
компилятор будет испускать код, эквивалентный this = dynamic; call Foo0Bar
, для передачи значения «динамический» непосредственно в месте, где «это» удерживается (регистр/адрес). В случае concrete.Bar
бетон будет находиться в стеке, поэтому он выдает немного другой код для загрузки смещения стека в один и тот же регистр/ячейку памяти и выполняет вызов. Сама функция не сможет сказать.
---- EDIT ----
Вот сборка из "г ++ -Wall -o TEST.exe -O1 test.cpp & & objdump -LSD TEST.exe | C++ фильт" с приведенный выше код, сосредоточившись на главной:
main():
400890: 53 push %rbx
400891: 48 83 ec 10 sub $0x10,%rsp
400895: bf 01 00 00 00 mov $0x1,%edi
40089a: e8 f1 fe ff ff callq 400790 <operator new(unsigned long)@plt>
40089f: 48 89 c3 mov %rax,%rbx
4008a2: be 01 00 00 00 mov $0x1,%esi
4008a7: 48 8d 7c 24 0f lea 0xf(%rsp),%rdi
4008ac: e8 47 00 00 00 callq 4008f8 <Foo::Bar(int)>
4008b1: be 02 00 00 00 mov $0x2,%esi
4008b6: 48 89 df mov %rbx,%rdi
4008b9: e8 3a 00 00 00 callq 4008f8 <Foo::Bar(int)>
4008be: 48 89 df mov %rbx,%rdi
4008c1: e8 6a fe ff ff callq 400730 <operator delete(void*)@plt>
4008c6: b8 00 00 00 00 mov $0x0,%eax
4008cb: 48 83 c4 10 add $0x10,%rsp
4008cf: 5b pop %rbx
4008d0: c3 retq
Наши вызовы функций члена здесь:
concrete.Bar (1)
4008a2: be 01 00 00 00 mov $0x1,%esi
4008a7: 48 8d 7c 24 0f lea 0xf(%rsp),%rdi
4008ac: e8 47 00 00 00 callq 4008f8 <Foo::Bar(int)>
dynamic-> Бар (2)
4008b1: be 02 00 00 00 mov $0x2,%esi
4008b6: 48 89 df mov %rbx,%rdi
4008b9: e8 3a 00 00 00 callq 4008f8 <Foo::Bar(int)>
Ясно, что «RDI» используется для того чтобы держать «этот», и первый использует стек-относительный адрес (с concrete
находится в стеке), а второй просто копирует значение «RBX», который имеет возвращаемое значение из «нового» ранее (mov %rax,%rbx
после вызова нового)
---- EDIT 2 ----
Помимо вызова функции сам, говоря с фактическими операциями, которые должны произойти при построении, срывании и доступе-значениях внутри объектов, стек обычно быстрее.
{
Foo concrete;
foo.Bar(1);
}
обычно занимает меньше циклов, чем
Foo* dynamic = new Foo;
dynamic->Bar(1);
delete dynamic;
, потому что второй вариант должен выделить память и, в общем, распределители памяти медленно (обычно они имеют какое-то замок в них для управления общим пул памяти).Кроме того, выделенная для этого память может быть кеш-холодная (хотя большинство распределителей запаса будут записывать данные блока на страницу, чтобы к тому времени, когда вы ее используете, он станет несколько теплым, но это может вызвать ошибку страницы, или вытолкнуть что-то еще из кеша).
Другим потенциальным преимуществом использования стека является общая когерентность кэширования.
int i, j, k;
Foo f1, f2, f3;
// ... thousands of operations populating those values
f1.DoCrazyMagic(f1, f2, f3, i, j, k);
Если нет внешних ссылок внутри DoCrazyMagic
, то все операции будут происходить в пределах небольшого населенного пункта памяти. И наоборот, если мы делаем
int *i, *j, *k;
Foo *f1, *f2, *f3;
// ... thousands of operations populating those values
f1->DoCrazyMagic(*f1, *f2, *f3, *i, *j, *k);
Вполне возможно, что в сложном сценарии переменные будут распространяться через несколько-страниц и может потребовать несколько ошибок страницы.
Однако, если «тысячи операций» являются достаточно интенсивными и сложными, область стека, где мы помещаем i, j, k, f1, f2 and f3
, может быть не более «горячей».
Путь другой: если вы злоупотребляете стеком, он также становится оспариваемым ресурсом, а преимущества по сравнению с использованием кучи становятся маргинальными или устраняются.
Обратите внимание, что оба используют 'this' внутренне, явно или неявно. – juanchopanza
Примечание: ваш второй «экземпляр» * не *; это объявление функции для функции под названием «inst», возвращающей значение объекта типа «T2» и не принимающее никаких параметров. Я думаю, что вы имели в виду 'T2 inst;' – WhozCraig
Я не уверен, что это связано с многопоточным, но если вам нужно какое-то представление о том, что это генерирует, напишите какой-то код и сгенерируйте asm и посмотрите, являются ли они одинаковыми и если нет, вы можете понять некоторые из них. Или вы можете вернуться и отправить пример кода –