>,c++,c++14,c++17"/>

首页 > 解决方案 > 移动 shared_ptr进入 shared_ptr>

问题描述

我试图避免一组普通旧数据结构的相当复杂的继承链,但我需要将它们全部存储在向量中+与调用者共享所有权。

Struct A {};
Struct B {};

using TInstruction = std::variant<A, B>;

struct holder {
  std::vector<std::shared_ptr<TInstruction>> items;
};

static holder h;

// Every individual TInstruction gets its own add function, for validation purposes
void add(std::shared_ptr<A> a) {
  // Somehow add this to h, while still sharing ownership with the caller
  // h.emplace_back(???)
}


int main() {
  holder h;

  auto a = std::make_unique<A>();
  auto b = std::make_unique<B>();

  add(a);
  // add(b) // not implemented
}

通过对原始想法的以下更改,我取得了中等(但令人讨厌的差)成功:

  1. 在变体中使用共享指针,即using TInstruction = std::variant<std::shared_ptr<A>, std::shared_ptr<B>>
  2. 接受一个 std::weak_ptr inadd().lock()用来将它变成一个 std::shared_ptr

我不介意#2(在我看来,这可能是正确的做法),但是将 shared_ptr 保持在它“外部”的变体内部会导致一些非常冗长的代码和模式匹配。

有可能做到这一点吗?我本质上想改变共享指针的类型,但仍然表达共享所有权的想法。

标签: c++c++14c++17

解决方案


只要您跟踪它自己持有的类型variant,您就可以利用shared_ptr<void>能够持有任何东西的优势,而不是使用,如下所示:shared_ptr

// Generic typelist
template <typename...>
struct Types;

// Find the 0-based index of type T in Types<...>
template <typename, typename>
struct Index;

// T is the first type in Types<...>
template <typename T, typename... Us> 
struct Index<T, Types<T, Us...>> : std::integral_constant<int, 0> {}; 

// T is not the first type in Types<...>
template <typename T, typename U, typename... Us> 
struct Index<T, Types<U, Us...>>
    : std::integral_constant<int, 1 + Index<T, Types<Us...>>()> {}; 

template <typename... Ts> 
struct SharedPtrVariant {
    template <typename T>
    explicit SharedPtrVariant(std::shared_ptr<T> p)
        : sp(std::move(p)), index(Index<T, Types<Ts...>>()) {}

    template <typename T>
    std::shared_ptr<T> get() const {
        return std::static_pointer_cast<T>(
            Index<T, Types<Ts...>>() == index ? sp : nullptr);
    }   

   private:
    std::shared_ptr<void> sp; 
    int index;
};

推荐阅读