Я пытаюсь улучшить свой код, используя интеллектуальные указатели, и в настоящее время пытаюсь заменить все старые необработанные указатели в нашей устаревшей кодовой базе на работе интеллектуальными указателями (std::unique_ptr и std::shared_ptr). Теперь у меня есть случай, когда указатель возвращается из статической функции.
Что произойдет, если я изменю это на std::shared_ptr, которое будет создано с помощью std::make_shared и возвращено из функции?
Сможет ли ref-count достичь 0, поскольку одна ссылка хранится внутри статической функции, или она останется до выхода из программы?
Предыдущий:
static MyObject* MyClass::createPointer()
{
return new MyObject();
}
Сейчас:
static std::shared_ptr<MyObject> MyClass::createSharedPointer()
{
return std::make_shared<MyObject>();
}
Поделитесь конкретикой.
@user12002570 user12002570 Я добавил фрагмент кода, показывающий, как выглядит статическая функция.
In my mind it will not be cleaned up until the program exits. Нет. Он будет удален, как только ref-count достигнет 0.
@ImanAbdollahzadeh Точно, и поскольку статическая функция будет существовать до выхода из программы, ref-count никогда не станет равным 0.
Вы неправильно поняли. Статическая функция не содержит ссылку на созданный указатель std::make_shared.
Можете ли вы удалить static из функции? То, что вы показали, кажется ненужным.
@ChukwujiobiCanon Нет? Будет ли оно передано тому std::shared_ptr, которому будет присвоено возвращаемое значение?
примечание: просто наклеивать std::shared_ptr на все, что не имеет дизайна, является излишним (и, вероятно, может привести к другим проблемам, таким как циклические зависимости. Убедитесь, что вы знаете, когда достаточно вернуть std::unique_ptr (это должен быть ваш второй выбор).
@ImanAbdollahzadeh: Это неправильный путь. Эта функция-член не нуждается в this, поэтому она должна быть static.





В старом коде возникает утечка памяти при следующем условии:
static MyObject* MyClass::createPointer()
{
return new MyObject(); /* <—- memory leak */
}Вы в конечном итоге delete то MyObject, которое создали? Если программа завершится, а вы этого не сделаете, то произойдет утечка памяти. Это не переменная static, а переменная dynamic, поэтому вы несете ответственность за delete.
На мой взгляд, он не будет очищен до выхода из программы.
В старом коде он даже не очистится, пока вы не очистите его сами.
В новом коде:
static std::shared_ptr<MyObject> MyClass::createSharedPointer()
{
return std::make_shared<MyObject>();
}Умный указатель будет обрабатывать deleteион за вас, так что это безопасно.
Сможет ли
ref-countдостичь 0, поскольку одна ссылка хранится внутри статической функции, или она останется до выхода из программы?
Внутри статической функции нет ссылки. В этом случае статическая функция ничем не отличается от нестатической функции.
Сама функция не ведет подсчет ссылок на создаваемый ею std::shared_ptr. Это делает std::shared_ptr, и это деталь реализации.
В старом коде указатель удаляется, но это не относится к вопросу, который я задаю. Что касается вашего вопроса, почему это статическая функция, у меня нет для вас ответа. Это было написано 15 лет назад человеком, который, вероятно, уже вышел на пенсию.
Я думаю, он был отмечен тегом static, потому что его нельзя было использовать где-либо еще во всем проекте.
@ImanAbdollahzadeh Я думаю, что они установили его как static, потому что хотели вызвать функцию без необходимости создания экземпляра объекта.
@ChukwujiobiCanon Возвращаюсь к моему первоначальному вопросу. Поскольку std::make_shared создается внутри статической функции, не достигнет ли ref_count 0 до выхода из программы?
@AndréLehto Я не такой уж эксперт в этом, но я предполагаю, что ваша функция static только создавала shared_ptr и все остальные usages этой памяти, увеличивая и уменьшая ref-count
Нет, функция сама по себе не ведет подсчет ссылок на создаваемый ею std::shared_ptr. Таким образом, сама статическая функция не будет иметь никакого влияния на количество ссылок созданного ею std::shared_ptr.
@ChukwujiobiCanon Хотите ли вы создать комментарий, разъясняющий этот вопрос, и я отмечу его как решение?
Я предполагаю, что вы тоже проголосуете :). Хорошо, речь идет о std::shared_ptr и о том, как интеллектуальный указатель обрабатывает подсчет ссылок, чтобы знать, когда delete динамически выделяемую переменную, на которую он указывает. Когда создается std::shared_ptr, он сохраняет счетчик ссылок равным 0. Всякий раз, когда он копируется, он увеличивает этот счетчик ссылок, а всякий раз, когда он выходит за пределы области действия, он уменьшает этот счетчик ссылок. Если счетчик ссылок равен 0 и выходит за пределы области видимости, это deletes память, на которую он указывает.
@ChukwujiobiCanon: У тебя static логика неправильная. Вы отмечаете функцию static, если она использует только члены класса static и не использует члены объекта (или this->). Эта функция настолько проста, что использует только конструктор. Для этого не требуется экземпляр объекта; на самом деле конструктор — это то, как вы создаете новый экземпляр объекта.
@MSalters Я все это понимаю, поэтому для начала попросил ОП. Из разговоров, которые у нас были в комментариях, вы увидите, что мы указали на это. ОП говорит: «У меня нет вам ответа. Оно было написано 15 лет назад кем-то, кто, вероятно, уже вышел на пенсию». сначала я думал, что это сделано для внутренней связи, но ОП указал, что эта функция является функцией-членом.
Не волнуйся. Современный компилятор C++ выполнит копирование в соответствии с вашим шаблоном кода. Неважно, статическая это функция или нет.
Но для std::shared_ptr необходимо его чему-то присвоить, иначе счетчик ссылок будет равен 0 (немедленное уничтожение объекта).
#include <memory>
#include <iostream>
struct MyObject
{
MyObject(int i):member{i}{
}
~MyObject(){
std::cout << "MyObject#" << member << " destruct\n";
}
static std::shared_ptr<MyObject> createPointer(int i){
return std::make_shared<MyObject>(i);
}
int member = 0;
};
static std::shared_ptr<MyObject> get_singleton_ptr(){
static auto ptr = std::make_shared<MyObject>(3);
return ptr;
}
MyObject& get_singleton_ref(){
static auto ptr = std::make_unique<MyObject>(4);
return *ptr;
}
int main() {
MyObject::createPointer(1);
auto ptr = MyObject::createPointer(2);
get_singleton_ptr();
get_singleton_ref();
std::cout << "end program/scope\n";
}
Результат должен быть
MyObject#1 destruct
end program/scope
MyObject#2 destruct
MyObject#4 destruct
MyObject#3 destruct
Логика «немедленно уничтожить объект» неверна. Если ваш shared_ptr не присвоен переменной, а является временным, то объект, на который указывает, уничтожается в конце полного выражения. Т.е. std::cout << *( std::make_shared<int>(42)); безопасно. Объект int уничтожается не сразу, а только после того, как он будет напечатан.
Вы должны показать нам точный код, чтобы получить точный/точный ответ. C++ слишком сложен, чтобы дать ответ, основываясь только на описании проблемы. Фрагмент кода сделает ваше сообщение более кратким. См. минимально воспроизводимый пример .