Я экспериментировал с shared_ptr
и make_shared
из C ++ 11 и запрограммировал небольшой игрушечный пример, чтобы увидеть, что на самом деле происходит при вызове make_shared
. В качестве инфраструктуры я использовал llvm / clang 3.0 вместе с библиотекой llvm std c ++ в XCode4.
class Object
{
public:
Object(const string& str)
{
cout << "Constructor " << str << endl;
}
Object()
{
cout << "Default constructor" << endl;
}
~Object()
{
cout << "Destructor" << endl;
}
Object(const Object& rhs)
{
cout << "Copy constructor..." << endl;
}
};
void make_shared_example()
{
cout << "Create smart_ptr using make_shared..." << endl;
auto ptr_res1 = make_shared<Object>("make_shared");
cout << "Create smart_ptr using make_shared: done." << endl;
cout << "Create smart_ptr using new..." << endl;
shared_ptr<Object> ptr_res2(new Object("new"));
cout << "Create smart_ptr using new: done." << endl;
}
Теперь посмотрите на вывод, пожалуйста:
Создать smart_ptr с помощью make_shared ...
Конструктор make_shared
Копировать конструктор ...
Копировать конструктор ...
Destructor
Destructor
Создать smart_ptr с помощью make_shared: done.
Создать smart_ptr, используя новый ...
Конструктор новый
Создать smart_ptr, используя new: done.
Destructor
Destructor
Похоже, что make_shared
вызывает конструктор копирования два раза. Если я выделю память для Object
, используя обычный new
, этого не произойдет, будет создан только один Object
.
Что меня интересует, так это следующее. Я слышал, что make_shared
должен быть более эффективным, чем new
( 1 , 2 ) . Одна из причин этого заключается в том, что make_shared
выделяет счетчик ссылок вместе с объектом, которым нужно управлять, в одном и том же блоке памяти. ОК, я понял. Это, конечно, более эффективно, чем две отдельные операции выделения.
Наоборот, я не понимаю, почему это должно сопровождаться стоимостью двух вызовов конструктора копирования Object
. Из-за этого я не уверен, что make_shared
более эффективно, чем распределение с использованием new
в в каждом случае. Я здесь не прав? Хорошо, можно реализовать конструктор перемещения для Object
, но все же я не уверен, является ли это более эффективным, чем простое распределение от Object
до new
. По крайней мере, не в каждом случае. Было бы верно, если бы копирование Object
обходилось дешевле, чем выделение памяти для счетчика ссылок. Но внутренний счетчик ссылок shared_ptr
может быть реализован с использованием нескольких примитивных типов данных, верно?
Можете ли вы помочь и объяснить, почему make_shared
- это путь с точки зрения эффективности, несмотря на намеченные издержки копирования?