访问向量的单端元素地址的有效方法

问题描述

我想实现一个迭代器,以便在for range循环中使用自定义类。迭代器访问基类的std::vector的内部std::unique_ptr,并返回指向子类的原始指针。

这是我想出的:

using upBase = std::unique_ptr<Base>;

class Test
{
   std::vector<upBase> list;
public:
   void Add(upBase&& i) { list.push_back(std::move(i)); }

   class iterator
   {
      upBase* ptr;
   public:
      iterator(upBase* p) : ptr(p)   {}
      bool         operator!=(const iterator& o) { return ptr != o.ptr; }
      iterator&    operator++()      { ++ptr; return *this; }
      Child&       operator*()       { return *(Child*)(*ptr).get(); }
      const Child& operator*() const { return *(Child*)(*ptr).get(); }

   };
   iterator begin() { return iterator(&list[0]); }
   iterator end()   { return iterator(&list[list.size()]); }
};

这在最新的编译器(在GodBolt上使用 GCC Clang MSVC 进行了测试)上很好用,但是在使用 Visual Studio 2015 ,end()方法会引发运行时异常:

 Debug assertion failed. C++ vector subscript out of range.

我在互联网上搜索了一种正确的方法来访问std::vector的单末尾元素的地址,但是除了复杂的指针运算法则之外什么也没找到。

我终于为begin()end()方法提出了以下实现:

iterator begin() { return iterator(&list.front()); }
iterator end()   { return iterator(&list.back() + 1); }

运行时不会抱怨。是访问std::arraystd::vector的单末尾元素地址的正确方法吗?

如果没有,正确的方法是什么?

解决方法

正确的方法是什么?

您正在尝试重新发明轮子。您无需为class iterator实现Test,因为您可以从list获取 begin end 迭代器(即 std::vector<upBase>::begin std::vector<upBase>::end

因此,只需通过Test类中的相应成员函数使它们可用:

class Test
{
    std::vector<upBase> list;
public:
    void Add(upBase&& i) { list.push_back(std::move(i)); }

    auto begin() /* const noexcept */ { return list.begin();  }
    auto end() /* const noexcept */ { return list.end(); }
};

See a demo here


还要注意,auto起才可能返回。如果编译器不支持C ++ 14,则可以将其提供为trailing return type,如下所示(假设至少您可以访问):

auto begin() -> decltype(list.begin()) { return list.begin();  }
auto end() ->  decltype(list.end())    { return list.end(); }

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...