簡體   English   中英

有沒有更好/安全的方法可以將shared_ptr的非常量引用轉換為基類?

[英]Is there a better/safe way to cast non-const reference of shared_ptr to a base class?

如果您有一個帶有虛擬方法的Base類和一個實現虛擬方法的Implementation類,是否有任何方法可以將std :: shared_ptr <Implementation>&強制轉換為std :: shared <Base>&? 編譯器允許使用const引用,但對於非const引用,它會失敗,如下面代碼中的“情況A”所示。 是否有捷徑可尋?

如果不是,在案例B中,我的解決方法“ questionable_cast”有多安全?

#include <iostream>
#include <memory>

class Base
{
public:
    virtual void set_value(int x) = 0;
};

class Implementation : public Base
{
public:
    Implementation() : m_value(0) { }
    void set_value(int x) override
    {
    m_value = x;
    }
    int get_value() const
    {
    return m_value;
    }
private:
    int m_value;
};


void do_something(std::shared_ptr<Base>& base)
{
    base->set_value(5);

    /// Code like this makes the non-const argument necessary
    base = std::make_shared<Implementation>();
}

template <class T, class U>
std::shared_ptr<T>& questionable_cast(std::shared_ptr<U>& u)
{
    /// This code is here to assure the cast is allowed
    std::shared_ptr<T> tmp = u;
    (void)tmp;

    return *reinterpret_cast<std::shared_ptr<T>*>(&u);
}

int main()
{
    std::shared_ptr<Implementation> a = std::make_shared<Implementation>();

    // The following line causes a compiler error:
    //  invalid initialization of reference of type ‘std::shared_ptr<Base>&’ ...
    // do_something(a);
    // do_something(std::dynamic_pointer_cast<Base>(a));

    // This is the workaround
    do_something(questionable_cast<Base>(a));

    std::cerr << "a = " << a->get_value() << std::endl;

    return 0;
}

最初問到的兩個明顯的解決方案:1.使do_something對shared_ptr(或按值指定shared_ptr)進行const引用。 2.創建一個名為shared_ptr並傳遞對此的引用:例如

int main()
{
    std::shared_ptr<Implementation> a = std::make_shared<Implementation>();
    std::shared_ptr<Base> b = a;  // This conversion works.
    do_something(b);  // Pass a reference to b instead.
    return 0;
}

您的questionable_cast函數違反了嚴格的別名規則,並調用了未定義的行為。 它很可能在初始測試中起作用,然后新版本的編譯器將優化提高了一個等級,並且在演示過程中將失敗。

要處理do_something更改指針的情況:

int main()
{
    std::shared_ptr<Implementation> a = std::make_shared<Implementation>();
    std::shared_ptr<Base> b = a;  // This conversion works.
    do_something(b);  // Pass a reference to b instead.
    const auto aa = std::dynamic_pointer_cast<Implementation>(b);
    if (aa)
        a = aa;
    else
        ; // Handle the error here
    return 0;
}

如果do_something保證返回相同派生類型的指針,即使它不返回相同的指針,也可以將其包裝在模板函數中:

template <typename T>
void do_something_ex( std::shared_ptr<T>& a )
{
    std::shared_ptr<Base> b = a;
    do_something(b)
    a = std::dynamic_pointer_cast<T>(b);
    if (!a)
        throw_or_assert;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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