簡體   English   中英

如何減少大量包裝類的實現代碼?

[英]How to reduce the implementation code of lots of wrapper classes?

我正在開發一個包含一些類的庫,我們稱它們為C1, C2 and... Cn 這些類中的每一個都實現了一些接口,即I1, I2, ... Im. (n > m)。 庫中對象之間的關系很復雜,我必須提供一些 API 供我的庫用戶使用智能指針訪問這些對象。

經過一番討論,我發現將共享指針返回給庫用戶並不是一個好主意,因為在這種情況下,我無法確保 object 可以在我的庫的 memory 中精確刪除。 返回弱指針也有同樣的問題,因為如果 API .lock()的用戶是弱指針並將結果共享指針保存在某處,我將再次面臨同樣的問題。

我的最后一個想法是為弱指針公開某種包裝器。 包裝器 class 可以是這樣的:

class Wrapper_C1 : public I1
{
   std::weak_ptr<C1> mC1;
public:
   Wrapper_C1() = delete;
   Wrapper_C1(const std::weak_ptr<C1> & c1) : mC1(c1)
   {
   }

   int method1_C1(int x)
   {
       if (auto sp = mC1.lock())
       {
           sp->method1_C1(x);
       }
       else
       {
            throw std::runtime_error("object C1 is not loaded in the lib.");
       }
   }

   void method2_C1(double y)
   {
       if (auto sp = mC1.lock())
       {
           sp->method2_C1(y);
       }
       else
       {
            throw std::runtime_error("object C1 is not loaded in the lib.");
       }
   }

   // The same for other methods
};

如您所見,所有這些包裝類都共享相同的實現。 減少所有這些包裝類的代碼的最佳方法是什么? 有沒有辦法避免重復類似的代碼?

如果您將 inheritance 放在包裝器中,您可能會執行以下操作來分解所有包裝器:

template <typename T>
class Wrapper
{
private:
   std::weak_ptr<T> m;
public:
   Wrapper() = delete;
   Wrapper(const std::weak_ptr<T> & w) : m(w) {}

   auto operator -> () /* const */
   {
       if (auto sp = m.lock())
       {
           return sp;
       }
       else
       {
            throw std::runtime_error("object is not loaded in the lib.");
       }
   }
};

您可以在不使用宏的情況下做的最好的事情(這在這里也無濟於事,要完全解決您的問題,我們需要某種 static 反射)是修復這些重復:

if (auto sp = mC1.lock())
{
    sp->method1_C1();
}
else
{
     throw std::Exception("object C1 is not loaded in the lib.");
}

我看到您可以輕松地將其簡化為模板 function ,如下所示:

template<class T, class R, class... Args>
R call_or_throw(const std::weak_ptr<T>& ptr, const std::string& error, R (T::*fun)(Args...), Args... args) {
    if (auto sp = ptr.lock()) 
    {
        return std::invoke(fun, *sp, args...);
    }
    else 
    {
        throw std::runtime_error(error.c_str());
    }
}

比你可以這樣使用它:

int method1_C1(int x)
{
    return call_or_throw(mC1, "object C1 is not loaded in the lib.", &C1::method1_C1, x);
}

void method2_C1(double y)
{
    return call_or_throw(mC1, "object C1 is not loaded in the lib.", &C1::method2_C1, y);
}

你甚至可以用它制作宏

對樹/圖形節點使用智能指針並不理想。 樹節點析構函數會破壞指向子節點的智能指針,而這些智能指針又會調用子節點析構函數,從而導致遞歸,當樹很深或可用堆棧大小很小時,可能會溢出堆棧。

另一種設計是擁有一棵樹 class 來管理其節點的生命周期並使用普通指針,例如std::map 並有一條規則,即刪除節點會使指向已刪除子樹的指針和引用無效。

這樣的設計簡單、健壯並且在運行時最有效。

暫無
暫無

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

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