簡體   English   中英

為智能指針編寫副本構造函數時遇到問題

[英]Problems writing a copy constructor for a smart pointer

我正在使用的代碼具有自己的智能指針實現,該指針實現了簡單的引用計數。 是的,我們不應該有自己的實現。 是的,我們應該使用boost或類似的方法。 忍受我。

我發現我想寫這樣的代碼:

...
CountedPointer<Base> base;
...
CountedPointer<Derived> derived;
...
base = derived;

但是,CountedPointer的副本構造函數具有如下原型:

CountedPointer(const CountedPointer<T> &other);

因此上述代碼將無法編譯,因為它找不到合適的構造函數(或賦值運算符-那里是相同的故事)。 我試圖用這樣的原型重寫復制構造函數:

template<U>
CountedPointer(const CountedPointer<U> &other);

但是,我遇到了一個問題,即復制構造函數必須訪問要復制的對象的私有成員(即原始指針),並且如果它在CountedPointer的不同專長中,則它們是不可見的。

Alexandrescu通過為封裝的指針提供訪問器功能來避免在其庫Loki中解決此問題,但我希望盡可能不要直接訪問原始指針。

有什么方法可以編寫此代碼,以允許派生到基本副本,但不允許對原始指針的常規訪問?

更新:我已經實現了下面可接受的答案,並且效果很好。 我花了一段時間才弄清楚為什么我的程序只提供復制構造函數的模板化版本,而不是原始的非模板化版本時,才出現嚴重錯誤。 最終,我意識到編譯器不會將模板版本視為復制構造函數,而是提供了默認版本。 默認值只是在不更新計數器的情況下愚蠢地復制內容,因此我最終得到了懸空的指針和雙重釋放。 同樣的事情也適用於賦值運算符。

你不能讓他們成為朋友嗎? 喜歡:

template<typename T>
class CountedPointer {

    // ...

    template<U>
    CountedPointer(const CountedPointer<U> &other);

    template<typename U> friend class CountedPointer;
};

“ Alexandrescu通過為封裝的指針提供訪問器功能,避免了在他的Loki庫中出現此問題,但如果可能的話,我不希望直接訪問原始指針”

我認為添加原始指針獲取器的成本將比嘗試避免沒有原始訪問的復雜性成本低得多。 只是沒有一種語言機制可以在兩個不相關的模板類之間轉換實例。 對於編譯器來說,它們是兩個完全不同的事物,在運行時沒有關系。 這就是為什么您一個模板類實例無法訪問其他私有實例的原因。

您可以考慮為所有CountedPointers的基類創建這種關系。 您可能必須在此基類中添加一個void *。 然后,您必須自己進行所有檢查(T是從U派生的,然后強制進行強制轉換...是否可以將T隱式轉換為U ?,如果這樣可以強制進行轉換..等),但這可能會變得非常復雜。 這是這種方法的一個粗略的開始:

class CountedPointerBase
{
    void* rawPtr;
};

template <class T>
class CountedPointer : public ConutedPointerBase
{
      T* myRawT = reinterpret_cast<T*>(rawPtr);

      template<class U>
      CountedPointer( CountedPointer<U> u)
      {
           // Copying a CountedPointer<T> -> CountedPointer<U>
           if (dynamic_cast<U*>(myRawT) != NULL)
           {
               // Safe to copy one rawPtr to another
           }
           // check for all other conversions
      }
}

查看兩種類型是否兼容,可能還有許多其他復雜性。 也許有一些Loki / Boost模板的技巧可以確定兩個類型參數是否可以轉換為另一個。

無論如何,正如您所看到的,這可能是一個復雜得多的解決方案,而不是添加吸氣劑。 能夠獲取原始指針還有其他好處。 例如,您可以將原始指針傳遞到僅接受原始指針的庫函數中,並將它們用作臨時指針。 我想,如果您團隊中的某人決定保留原始指針的副本而不是智能ptr,則可能會很危險。 那個人大概應該被鱒魚打耳光。

如果您有CountedPointer(T * other),則將解決問題。 構造函數和類似的賦值運算符。

暫無
暫無

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

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