簡體   English   中英

處理stl容器中的智能指針

[英]Handling smart pointers in stl container

我有一個類Foo<T> ,它有一個指向Shape派生類的智能指針。 我正在嘗試實現at(index)成員函數。 這是我要直觀地做的事情:

Foo<float> myfoo;
std::unique_ptr<Shape<float>> shape_ptr = myfoo.at(i);
shape_ptr->doSomething(param1, param2, ...);

在定義at(index)函數時,我收到編譯器錯誤消息。 請注意,定義了移動構造函數,並且Shape基類是抽象的。 下面,我將提供一些代碼用於說明目的。

此外,我最近在網上找到了一個關於如何使用std::move重載賦值運算符的示例。 我通常遵循Copy-Swap習語。 重載上述操作符的兩種方法中的哪一種對我的情況有意義? 下面,我還說明了函數的定義。

template < typename T >
class Foo{

    public:

        Foo();
        Foo( Foo && );
        ~Foo();

        void swap(Foo<T> &);
        //Foo<T> & operator =( Foo<T> );
        Foo<T> & operator =( Foo<T> && );

        std::unique_ptr<Shape<T> > at ( int ) const; // error here!

        int size() const;

    private:

        std::vector< std::unique_ptr<Shape<T> > > m_Bank;
};

template < typename T >
Foo<T>::Foo( Foo && other)
    :m_Bank(std::move(other.m_Bank))
{

}

/*template < typename T >
void Filterbank<T>::swap(Filterbank<T> & refBank ){

    using std::swap;
    swap(m_Bank, refBank.m_Bank);
}

template < typename T >
Foo<T> & Filterbank<T>::operator =( Foo<T> bank ){

    bank.swap(*this);
    return (*this);
}*/

template < typename T >
Foo<T> & Foo<T>::operator =( Foo<T> && bank ){

    //bank.swap(*this);
    m_Bank = std::move(bank.m_Bank);
    return (*this);
}

template < typename T >
std::unique_ptr<Shape<T> > Foo<T>::at( int index ) const{
    return m_Bank[index]; // Error here! => error C2248: 'std::unique_ptr<_Ty>::unique_ptr' : cannot access private member declared in class 'std::unique_ptr<_Ty>'
}

使用Boost的指針容器而不是帶unique_ptr的標准容器。 它們是為這種用途而設計的。

我認為你應該在這里使用shared_ptr

只有一個unique_ptr可以擁有共享資源。 如果你能夠做你想做的事情,即按值返回unique_ptr那么向量中的那個將被銷毀 ,這可能是你不想要的。

Q1:如何處理Foo::at( int ) const ,以便您可以:

myfoo.at(i)->doSomething(param1, param2, ...);

不將所有權轉移出vector<unique_ptr<Shape<T>>>

A1: Foo::at( int ) const應該返回一個const std::unique_ptr<Shape<T> >&

template < typename T >
const std::unique_ptr<Shape<T> >&
Foo<T>::at( int index ) const
{
    return m_Bank[index];
}

現在你可以取消引用const unique_ptr並調用他們想要的任何Shape成員(const或非const)。 如果他們不小心嘗試復制unique_ptr (它會將所有權轉移出Foo ),他們將收到編譯時錯誤。

這個解決方案比將非const引用返回到unique_ptr要好,因為它會捕獲Foo意外所有權轉移。 但是,如果您希望允許從Foo通過at進行所有權轉移,那么非const引用將更合適。

Q2:此外,我最近在網上找到了一個關於如何使用std :: move重載賦值運算符的示例。 我通常遵循Copy-Swap習語。 重載上述操作符的兩種方法中的哪一種對我的情況有意義?

A2:我不確定~Foo()作用。 如果它沒有做任何事情,你可以刪除它,然后(假設完全符合C ++ 11)你將自動獲得正確和最佳的移動構造函數和移動賦值運算符(以及正確刪除的復制語義)。

如果你不能刪除~Foo() (因為它做了一些重要的事情),或者你的編譯器還沒有實現自動移動生成,你可以明確地提供它們,就像你在問題中所做的那樣。

你的移動構造函數是現場:移動構造成員。

您的移動分配應該類似(並且如果~Foo()是隱式的,則會自動生成):移動分配成員:

template < typename T >
Foo<T> & Foo<T>::operator =( Foo<T> && bank )
{
    m_Bank = std::move(bank.m_Bank);
    return (*this);
}

你的Foo設計也適用於Swappable ,這總是很好供應:

friend void swap(Foo& x, Foo& y) {x.m_Bank.swap(y.m_Bank);}

如果沒有這種明確的swap ,你Foo還是Swappable使用Foo的舉動構造函數和移動賦值。 然而,這種顯式swap速度大約是隱式swap的兩倍。

以上建議都旨在獲得Foo最高性能。 如果需要,您可以在移動作業中使用復制交換習語。 這將是正確的,稍慢。 雖然如果你小心你沒有通過swap調用移動賦值和移動賦值調用swap獲得無限遞歸! :-)確實,這個問題只是干凈(和最佳)分離swap和移動分配的另一個原因。

更新

假設Shape看起來像這樣 ,這里有一種方法可以為Foo編寫移動構造函數,移動賦值,復制構造函數和復制賦值運算符,假設Foo有一個數據成員:

std::vector< std::unique_ptr< Shape > > m_Bank;

...

Foo::Foo(Foo&& other)
    : m_Bank(std::move(other.m_Bank))
{
}

Foo::Foo(const Foo& other)
{
    for (const auto& p: other.m_Bank)
        m_Bank.push_back(std::unique_ptr< Shape >(p ? p->clone() : nullptr));
}

Foo&
Foo::operator=(Foo&& other)
{
    m_Bank = std::move(other.m_Bank);
    return (*this);
}

Foo&
Foo::operator=(const Foo& other)
{
    if (this != &other)
    {
        m_Bank.clear();
        for (const auto& p: other.m_Bank)
            m_Bank.push_back(std::unique_ptr< Shape >(p ? p->clone() : nullptr));
    }
    return (*this);
}

如果您的編譯器支持默認的移動成員,則可以通過以下方式實現同​​樣的目的:

    Foo(Foo&&) = default;
    Foo& operator=(Foo&&) = default;

用於移動構造函數和移動賦值運算符。

以上確保每個Shape始終只由一個智能指針/向量/ Foo擁有。 如果您希望多個Foo共享Shape的所有權,那么您可以擁有作為您的數據成員:

std::vector< std::shared_ptr< Shape > > m_Bank;

並且您可以默認所有移動構造函數,移動賦值,復制構造函數和復制賦值。

看起來你應該在這里返回一個引用:

Shape<T> & Foo<T>::at( int index ) const{
    return *m_Bank[index];
}

暫無
暫無

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

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