Я знаю, что это уже давно, но теперь я чувствую, что мы имеем дело с C ++ 11-17, кто-то должен упоминать лямбда. Если вы запишете это в лямбду, которая будет вызываться асинхронно в более поздний момент времени, возможно, что ваш «этот» объект будет уничтожен до того, как эта лямбда будет вызвана.
, т.е. передавая ее как callback к некоторой дорогостоящей функции, которая запускается из отдельного потока или просто асинхронно вообще
EDIT: для того, чтобы быть понятным, вопрос: «Имеет ли смысл проверять, является ли это нулевым» I просто предлагаю сценарий, где это имеет смысл, который может стать более распространенным с более широким использованием современного C ++.
Продуманный пример: этот код полностью работоспособен. Чтобы увидеть небезопасное поведение, просто закомментируйте вызов безопасного поведения и раскомментируйте небезопасный позывной.
#include <memory>
#include <functional>
#include <iostream>
#include <future>
class SomeAPI
{
public:
SomeAPI() = default;
void DoWork(std::function<void(int)> cb)
{
DoAsync(cb);
}
private:
void DoAsync(std::function<void(int)> cb)
{
std::cout << "SomeAPI about to do async work\n";
m_future = std::async(std::launch::async, [](auto cb)
{
std::cout << "Async thread sleeping 10 seconds (Doing work).\n";
std::this_thread::sleep_for(std::chrono::seconds{ 10 });
// Do a bunch of work and set a status indicating success or failure.
// Assume 0 is success.
int status = 0;
std::cout << "Executing callback.\n";
cb(status);
std::cout << "Callback Executed.\n";
}, cb);
};
std::future<void> m_future;
};
class SomeOtherClass
{
public:
void SetSuccess(int success) { m_success = success; }
private:
bool m_success = false;
};
class SomeClass : public std::enable_shared_from_this<SomeClass>
{
public:
SomeClass(SomeAPI* api)
: m_api(api)
{
}
void DoWorkUnsafe()
{
std::cout << "DoWorkUnsafe about to pass callback to async executer.\n";
// Call DoWork on the API.
// DoWork takes some time.
// When DoWork is finished, it calls the callback that we sent in.
m_api->DoWork([this](int status)
{
// Undefined behavior
m_value = 17;
// Crash
m_data->SetSuccess(true);
ReportSuccess();
});
}
void DoWorkSafe()
{
// Create a weak point from a shared pointer to this.
std::weak_ptr<SomeClass> this_ = shared_from_this();
std::cout << "DoWorkSafe about to pass callback to async executer.\n";
// Capture the weak pointer.
m_api->DoWork([this_](int status)
{
// Test the weak pointer.
if (auto sp = this_.lock())
{
std::cout << "Async work finished.\n";
// If its good, then we are still alive and safe to execute on this.
sp->m_value = 17;
sp->m_data->SetSuccess(true);
sp->ReportSuccess();
}
});
}
private:
void ReportSuccess()
{
// Tell everyone who cares that a thing has succeeded.
};
SomeAPI* m_api;
std::shared_ptr<SomeOtherClass> m_data = std::shared_ptr<SomeOtherClass>();
int m_value;
};
int main()
{
std::shared_ptr<SomeAPI> api = std::make_shared<SomeAPI>();
std::shared_ptr<SomeClass> someClass = std::make_shared<SomeClass>(api.get());
someClass->DoWorkSafe();
// Comment out the above line and uncomment the below line
// to see the unsafe behavior.
//someClass->DoWorkUnsafe();
std::cout << "Deleting someClass\n";
someClass.reset();
std::cout << "Main thread sleeping for 20 seconds.\n";
std::this_thread::sleep_for(std::chrono::seconds{ 20 });
return 0;
}
Взгляните на описание правила .
Если явно не объявить видимость переменной-члена, это может привести к тому, что вы будете иметь видимость, которую вы не ожидаете, и потенциально оставить ее открытой для неожиданного изменения другими классами.
blockquote>Если у вас есть свойство пакета класса private, тогда любой класс в этом же пакете может изменить это свойство.
Но у пакета Private все еще есть действительное использование. Например, вы можете объявить класс как частный пакет, чтобы его можно было использовать внутри пакета, в котором он объявлен, но остается скрытым от публичного использования.