簡體   English   中英

指向靜態const對象的共享指針?

[英]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;
}

Demo on coliru

智能指針shared_ptrunique_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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM