exponenta event banner

Использование new или make_unique вместо более эффективного make_shared

Используя new или make_unique для инициализации или сброса shared_ptr приводит к дополнительному выделению памяти

Описание

Этот дефект возникает при использовании:

  • new или make_unique для инициализации shared_ptr экземпляр. Например:

    std::shared_ptr<T> p1(new T());
    std::shared_ptr<T> p2(make_unique<T>());

  • new для сброса shared_ptr экземпляр. Например:

    std::shared_ptr<T> p1;
    //...
    p1.reset(new T);

Вы используете shared_ptr экземпляры, когда требуется, чтобы несколько смарт-указателей владели одним и тем же объектом и управляли им. Экземпляры также совместно используют блок управления, содержащий число экземпляров, которым принадлежит управляемый объект.

Polyspace ® не помечает использование new для инициализации shared_ptr экземпляр в частных или защищенных конструкторах. Например, никакой дефект не поднят на использовании new в этом фрагменте кода:

class PrivateCTor
{
public:
    static std::shared_ptr<PrivateCTor> makeOne()
    {
        return std::shared_ptr<PrivateCTor>(new PrivateCTor);
    }
private:
    PrivateCTor();
};

Риск

При использовании new или make_unique для инициализации shared_ptr при выполнении дополнительной операции выделения создается хранилище для блока управления. Адрес дополнительного выделения может находиться на другой странице памяти или вне кэша данных по сравнению с адресом управляемого объекта.

Зафиксировать

Использовать std::make_shared для инициализации shared_ptr экземпляр. Функция выполняет одну операцию выделения с достаточным объемом памяти для хранения управляемого объекта и блока управления.

Повышение производительности может зависеть от используемого компилятора, реализации библиотеки и среды.

Примеры

развернуть все

#include <memory>
#include <string>

struct Profile {
    virtual ~Profile() = default;
};

struct Player : public Profile {
    std::string name;
    std::int8_t rank;

    Player();
    Player(const std::string& name_, const std::int8_t& rank_) :
        name{ name_ }, rank{ rank_ } {}
};

void func()
{

    std::shared_ptr<Player> player1(new Player("Serena Williams", 1));
    std::shared_ptr<Player> top_rank(player1);

}

В этом примере Polyspace помечает использование new инициализировать player1. Программа выполняет дополнительную операцию выделения для управляющего блока, который содержит счетчик всех экземпляров shared_ptr которые владеют управляемыми Player объект.

Коррекция - использование std::make_shared Инициализировать shared_ptr

Одной из возможных корректировок является использование std::make_shared инициализировать player1.

#include <memory>
#include <string>

struct Profile {
    virtual ~Profile() = default;
};

struct Player : public Profile {
    std::string name;
    std::int8_t rank;

    Player();
    Player(const std::string& name_, const std::int8_t& rank_) :
        name{ name_ }, rank{ rank_ } {}
};

void func()
{

    auto player1 = std::make_shared<Player>("Serena Williams", 1);
    std::shared_ptr<Player> top_rank(player1);

} 

Информация о результатах

Группа: Производительность
Язык: C++
По умолчанию: Откл.
Синтаксис командной строки: MISSING_MAKE_SHARED
Воздействие: Низкий
Представлен в R2021a