Действительно ли make_shared более эффективен, чем новый?

Я экспериментировал с 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("make_shared");
    cout << "Create smart_ptr using make_shared: done." << endl;

    cout << "Create smart_ptr using new..." << endl;
    shared_ptr ptr_res2(new Object("new"));
    cout << "Create smart_ptr using new: done." << endl;
}

Теперь взгляните на результат, пожалуйста:

Создайте smart_ptr, используя make_shared ...

Конструктор make_shared

Конструктор копирования ...

Конструктор копирования ...

Деструктор

Деструктор

Создайте smart_ptr, используя make_shared: done.

Создайте smart_ptr, используя new ...

Конструктор new

Создайте smart_ptr, используя new: done.

Деструктор

Деструктор

Похоже, что make_shared вызывает конструктор копирования два раза. Если я выделяю память для объекта , используя обычный новый , этого не происходит, создается только один объект .

Меня интересует следующее. Я слышал, что make_shared должен быть более эффективным, чем использование new ( 1 , 2 ) . Одна из причин заключается в том, что make_shared выделяет счетчик ссылок вместе с объектом, которым нужно управлять, в том же блоке памяти. Хорошо, я понял.Это, конечно, более эффективно, чем две отдельные операции распределения.

Напротив, я не понимаю, почему это связано с затратами двух вызовов конструктора копирования Object . Из-за этого я не уверен, что make_shared более эффективен, чем распределение с использованием new в в каждом случае. Я здесь не прав? Хорошо, хорошо, можно было бы реализовать конструктор перемещения для объекта , но все же я не уверен, что это более эффективно, чем просто размещение объекта через new . По крайней мере, не во всех случаях. Было бы верно, если бы копирование объекта было бы дешевле, чем выделение памяти для счетчика ссылок. Но внутренний счетчик ссылок shared_ptr может быть реализован с использованием пары примитивных типов данных, верно?

Можете ли вы помочь и объяснить, почему make_shared - это способ пойти с точки зрения эффективность, несмотря на указанные накладные расходы на копирование?

50
задан Nic Hartley 27 October 2017 в 07:32
поделиться