容器的 begin() 和 end() 的不同实现

iam*_*gan 4 c++ containers iterator

我正在练习实施容器。我的目标是定义迭代器begin()end() 以便我可以使用for(auto x : v). 我的容器看起来像这样:

class Vector{
public:
    Vector(initializer_list<double> numbers){
        sz = numbers.size();
        elem = new double[sz];
        int i = 0;
        for (auto it = numbers.begin(); it!=numbers.end(); ++it)
            elem[i++] = *it;
    }
    ~Vector(){delete [] elem;}
    double* begin();
    double* end();
private:
    double* elem;
    int sz;
    
};
Run Code Online (Sandbox Code Playgroud)

选项1

这就是我定义迭代器的方式(它们在我的测试用例中工作得很好)

double* Vector::begin(){
    return elem;
}

double* Vector::end(){
    return &elem[sz];
}

Run Code Online (Sandbox Code Playgroud)

选项 2

这就是它们在A Tour of C++中的定义

double* Vector::begin(){
    return &elem[0];
}

double* Vector::end(){
    return &elem[0]+sz;
}

Run Code Online (Sandbox Code Playgroud)

我的问题

据我所知,这两个选项都可以正常工作(假设容器非空)。与选项 1 相比,选项 2 有什么优势(反之亦然)?我很感激任何建议。

Nat*_*ica 9

虽然&elem[sz]并且&elem[0]+sz最终会在大多数/所有系统上为您提供相同的结果,但第一个实际上是未定义的行为。当你做

&elem[sz]
Run Code Online (Sandbox Code Playgroud)

你实际上在做

&*(elem +sz)
Run Code Online (Sandbox Code Playgroud)

而那个*,取消引用,是对一个不存在的元素。这是 C++ 标准中未定义的行为。

&elem[0]+sz
Run Code Online (Sandbox Code Playgroud)

你得到一个指向第一个合法元素的指针,只要该指针指向一个实际的数组,然后你将它推进到最后一个。这是获得提供的结束迭代器的合法且正确的方法elem不为空并指向有效数组。


另一种方法是使用

return elem + sz;
Run Code Online (Sandbox Code Playgroud)

因为它不需要任何取消引用。