访问向量的尾数元素地址的有效方法
Valid way of accessing the address of the one-past-end element of a vector
我想实现一个迭代器以在 for range 循环中使用自定义 class。迭代器访问 Base class 的 std::unique_ptr
的内部 std::vector
和 returns 指向子 class.
的原始指针
这是我想出的:
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.
我在 Internet 上搜索了一种访问 std::vector
的尾数元素地址的正确方法,但除了复杂的指针运算外没有找到任何东西。
我最终为 begin()
和 end()
方法提出了以下实现:
iterator begin() { return iterator(&list.front()); }
iterator end() { return iterator(&list.back() + 1); }
这在 运行 时没有抱怨。这是访问 std::array
或 std::vector
的尾数元素地址的正确方法吗?
如果不是,正确的方法是什么?
What would be the proper way?
您正在尝试 re-invent 方向盘。您不需要为您的 Test
实现 class iterator
,因为您可以从list
(即 std::vector<upBase>::begin
和 std::vector<upBase>::end
)
因此只需通过 Test
class:
中相应的成员函数使它们可用
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(); }
};
另请注意,auto
return 仅在 c++14. If the compiler does not support C++14, you can provide it as trailing return type, as follows (assuming at least you have access to c++11 之后才有可能):
auto begin() -> decltype(list.begin()) { return list.begin(); }
auto end() -> decltype(list.end()) { return list.end(); }
我想实现一个迭代器以在 for range 循环中使用自定义 class。迭代器访问 Base class 的 std::unique_ptr
的内部 std::vector
和 returns 指向子 class.
这是我想出的:
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.
我在 Internet 上搜索了一种访问 std::vector
的尾数元素地址的正确方法,但除了复杂的指针运算外没有找到任何东西。
我最终为 begin()
和 end()
方法提出了以下实现:
iterator begin() { return iterator(&list.front()); }
iterator end() { return iterator(&list.back() + 1); }
这在 运行 时没有抱怨。这是访问 std::array
或 std::vector
的尾数元素地址的正确方法吗?
如果不是,正确的方法是什么?
What would be the proper way?
您正在尝试 re-invent 方向盘。您不需要为您的 Test
实现 class iterator
,因为您可以从list
(即 std::vector<upBase>::begin
和 std::vector<upBase>::end
)
因此只需通过 Test
class:
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(); }
};
另请注意,auto
return 仅在 c++14. If the compiler does not support C++14, you can provide it as trailing return type, as follows (assuming at least you have access to c++11 之后才有可能):
auto begin() -> decltype(list.begin()) { return list.begin(); }
auto end() -> decltype(list.end()) { return list.end(); }