[英]Shared pointer to a static const object?
對於上下文,我正在實現一個用戶訪問系統,人們可以在其中登錄我的應用程序。 指向CUser
的指針可以訪問當前登錄的用戶:
std::shared_ptr<CUser> m_pCurrentUser;
當用戶注銷時,我希望此指針指向已聲明為靜態const的“默認”用戶:
static const CUser xDefaultUser(L"Default", L"password", CUser::EAccessLevels::eAnon);
我的第一個問題是將靜態const應用於默認用戶對象是否正確。 我的理由是,它永遠都不應更改(const),並且我希望它在應用程序的生命周期內可用(靜態)。
第二個問題是我應該如何將默認用戶分配為m_pCurrentUser
。 我是否應該聲明一個const shared_ptr<CUser>
而不是一個簡單的對象?
將指向靜態對象的指針分配給shared_ptr
並不是一個好主意。 您將得到內存損壞,因為ptr不擁有此內存:
shared_ptr<CUser> ptr = &xDefaultUser;
ptr = nullptr; // crash
您可以使用默認對象創建static const shared_ptr
。 在這種情況下,內存不會被破壞。 看下面的例子:
#include <string>
#include <memory>
#include <iostream>
class User {
public:
User(const std::string& name)
: _name(name)
{}
~User() { std::cout << "Bye, " << _name << std::endl; }
void print() { std::cout << _name << std::endl; }
private:
std::string _name;
};
static const std::shared_ptr<User> s_defaultUser = std::make_shared<User>("<default>");
class UserMgr {
public:
UserMgr()
: m_current(s_defaultUser)
{}
void MakeCurrent(std::shared_ptr<User> u) {
if (u) {
m_current = u;
} else {
m_current = s_defaultUser;
}
}
std::shared_ptr<User> GetCurrent() { return m_current; }
private:
std::shared_ptr<User> m_current;
};
int main() {
UserMgr mgr;
mgr.MakeCurrent(std::make_shared<User>("User 1"));
mgr.GetCurrent()->print();
mgr.MakeCurrent(std::make_shared<User>("User 2"));
mgr.GetCurrent()->print();
mgr.MakeCurrent(std::make_shared<User>("User 3"));
mgr.GetCurrent()->print();
mgr.MakeCurrent(nullptr);
mgr.GetCurrent()->print();
return 0;
}
智能指針shared_ptr
和unique_ptr
必須擁有它們指向的對象,並且在不再需要它時將其刪除。
當然,您可以隨時這樣做:
m_pCurrentUser = std::make_shared(xDefaultUser);
什么都不會中斷,通過指針將保存您的靜態const對象的副本 。 僅原始指針或weak_ptr
不關心所有權。
因此,如果您可以接受復制靜態const對象的開銷,請按照這種方式進行:保持干凈的智能指針處理。
如果您不能接受,則必須構建一個特殊的智能指針類,該智能指針通常表現為shared_ptr
但在特殊情況下也無法破壞其指向的對象。 一種簡單的方法是擁有一個bool owner
成員,該成員應該在刪除指針對象之前進行測試。 我不確定它的所有含義,所以如果可以的話,我的建議是避免使用
訪問器方法怎么樣?
const CUser* GetCurrentUser()
{
return (m_pCurrentUser == nullptr) ? &xDefaultUser : m_pCurrentUser.get();
}
它允許您控制對用戶的訪問(例如,在非const
版本中,您可以返回副本或空指針),並且可以防止您不得不解決在注銷時忘記將m_pCurrentUser
設置為默認用戶的錯誤。最終為空。
您需要一個額外的指針“狀態”,表示“用戶已注銷”,這與“未初始化的用戶”(將為nullptr)不同。 您可以使用std :: variant來實現(如果可以使用C ++ 17,否則boost :: variant也應該可以)
#include <memory>
#include <variant>
#include <iostream>
struct LoggedOut{
int operator*(){return 50;}
};
int main(){
std::variant<std::shared_ptr<int>, LoggedOut> pCurrentUser(nullptr);
{
pCurrentUser = std::make_shared<int>(1);
auto newuser = pCurrentUser;
}
std::cout<< *std::get<0>(pCurrentUser)<<"\n";
auto logout = [](auto& p){ p=LoggedOut(); };
logout(pCurrentUser);
std::cout<<*std::get<1>(pCurrentUser)<<"\n"; //prints 50
//std::cout<<*std::get<0>(pCurrentUser)<<"\n"; //runtime error: bad variant access
}
如果您不想使用std :: get,則可以輕松地將它們隱藏在自定義指針類中,
#include <memory>
#include <variant>
#include <iostream>
struct LoggedOut{
int operator*(){return 50;}
};
template<typename T>
struct myPointer : public std::variant<std::shared_ptr<int>, LoggedOut>{
using super = std::variant<std::shared_ptr<int>, LoggedOut>;
using super::variant;
auto operator*(){ return std::get_if<0>(this) ? *std::get<0>(*this) : *std::get<1>(*this); }
};
int main(){
myPointer<int> pCurrentUser(nullptr);
{
pCurrentUser = std::make_shared<int>(1);
auto newuser = pCurrentUser;
}
std::cout<< *pCurrentUser<<"\n";
auto logout = [](auto& p){ p=LoggedOut(); };
logout(pCurrentUser);
std::cout<<*pCurrentUser<<"\n";
std::cout<<*std::get<0>(pCurrentUser)<<"\n"; //runtime error: bad variant access
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.