c++ - 统一迭代 std::vector<T> 和 std::vector<unique_ptr<T>>

标签 c++ c++11 vector stl

我经常遇到这样的情况,我引入了一个抽象基类(称为 Foo )来将不同子类的实例(称为 BarBaz )存储在容器中(例如 std::vector<std::unique_ptr<Foo>> ) .为了便于说明,让我将这些示例类放在这里:

class Foo {
public:
    virtual int getId() const = 0;
};

class Bar : public Foo {
public:
    Bar(int id) : id_(id) {}
    int getId() const override { return id_; }
private:
    int id_;
};

class Baz : public Foo {
public:
    Baz(int id) : id_(id) {}
    int getId() const override { return id_; }
private:
    int id_;
};

如果我实现一个函数来遍历 std::vector<std::unique_ptr<Foo>> , 看起来像

template<class InputIterator>
void printIds(InputIterator first, InputIterator last) {
    for (; first != last; ++first)
        std::cout << (*first)->getId() << std::endl;
}

但是,如果我还想允许迭代homogeneous 类型的 vector (例如 std::vector<Bar> )而不重写整个函数(或可能的其他类似类型的函数)怎么办?我看到两种明显的可能性:

1)实现功能

template<class Type>
const Type & dereference(const Type &value) {
    return value;
}

template<class Type>
const Type & dereference(const std::unique_ptr<Type> &value) {
    return *value;
}

并替换

std::cout << (*first)->getId() << std::endl;

通过

std::cout << dereference(*first).getId() << std::endl;

2)实现功能

template<class Type>
int getId(const Type &value) {
    return value.getId();
}

template<class Type>
int getId(const std::unique_ptr<Type> &value) {
    return value->getId();
}

并替换

std::cout << (*first)->getId() << std::endl;

通过

std::cout << getId(*first) << std::endl;

选项 1) 似乎是处理 Type & 类型引用的一般可能性(或 const Type & )和 std::unique_ptr<Type> (甚至 Type *const Type * )统一。但是,我还没有看到它在生产代码中被大量使用。这是避免代码重复的常见模式吗?或者有更好的方法来处理这个问题吗?

最佳答案

我会写 get_ptr<T> .

get_ptr<T*>如果失败则返回 nullptr。

如果传递了对可转换为 T* 的内容的引用, 它返回它。

如果传递了对可转换为 T& 的内容的引用, 它返回一个指向它的指针。

否则,如果传递一个指针,如果指针为 null 则返回 null 并且 get_ptr<T>(*ptr)如果指针不为空。

否则,如果x.get()返回一个指针,它返回 get_ptr<T>(x.get()) .

现在printIds阅读:

template<class InputIterator>
void printIds(InputIterator first, InputIterator last) {
  for (; first != last; ++first)
    std::cout << get_ptr<Foo>(*first)->getId() << std::endl;
}

请注意 get_ptr 的可能性失败在这里相当明显。


如果你不想硬编码类型 T ,我们可以更进一步。

如果get_obj_ptr传递一个指向指针的指针,并且指针不为空,它取消引用指针并递归。如果为 null,则返回转换为相同类型的 nullptr。

如果通过了谁的类(class).get()返回一个指针,它在 get_obj_ptr(x.get()) 上递归.

否则,如果get_obj_ptr(x)传递一个指针,它返回 x .

否则,如果get_obj_ptr(x)传递一个左值,它返回 std::addressof(x) .

与您的代码不同,它承认失败的可能性。

template<class InputIterator>
void printIds(InputIterator first, InputIterator last) {
  for (; first != last; ++first)
    auto* ptr = get_obj_ptr(*first);
    if (ptr)
      std::cout << ptr->getId() << std::endl;
    else
      std::cout << "null object" << std::endl;
}

作为一般规则,采用智能指针并假设它们永远不会为 null 是一个坏主意。

关于c++ - 统一迭代 std::vector<T> 和 std::vector<unique_ptr<T>>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45286632/

相关文章:

c++ - 如何在 C++ 中将 auto 与 const 和 & 一起使用?

c++ - 如何将对象分配给与 operator= 不匹配的 2d vector

c++ - 运行 C++ 程序时出现 0xc000007b 错误

c++ - 将对象从 C++ 发送到 qml。空闲内存呢?

c++ - C++中的客户端/服务器程序问题

c++ - 删除[]后剩余的堆数组的剩余元素

c - GCC 内联 SSE 代码

c++ - wxWidgets 在调用 wxApp::OnInit 之前退出

c++ - 写智能指针和指针的泛型代码时,如何获取简单指针?

c++ - 如何在两个 STL 容器之间移动 unique_ptr 对象