C++ 如果向量为空,std::vector::data()应该返回什么?

C++ 如果向量为空,std::vector::data()应该返回什么?,c++,vector,C++,Vector,根据标准草案(),data()指向基础数组,[data(),data()+size())必须是有效范围: T* data() noexcept; const T* data() const noexcept; 1 Returns: A pointer such that [data(),data() + size()) is a valid range. For a non-empty vector, data() == &front(). 2 Complexity:

根据标准草案(),data()指向基础数组,
[data(),data()+size())
必须是有效范围:

T* data() noexcept;
const T* data() const noexcept;

    1 Returns: A pointer such that [data(),data() + size()) is a valid range. For a non-empty vector,
data() == &front().
    2 Complexity: Constant time
但是如果向量是空的呢?当我构造一个零大小的向量时:

#include <vector>
#include <iostream>

int main() {
    const int NUM = 0*10;
    std::vector< double > v( NUM, 0.0 );
    std::cerr << "V : "<< v.data() << std::endl;
}
#包括
#包括
int main(){
常数int NUM=0*10;
标准:向量v(NUM,0.0);

std::cerr存在一种状态,即对象可以是有效的,但不能指定:

有效但未指定的状态[§17.3]

除对象的 满足不变量,对象上的操作按指定方式进行 就其类型而言

[示例:如果std::vector类型的对象x位于有效但 未指定状态,可以无条件调用x.empty(),并且 x、 只有当x.empty()返回false时才能调用front()。-结束示例]

读取C++标准时,在向量为空时,不指定“代码>数据())/代码>状态。因此,状态是有效的但未指定状态。因此,当vector为空时,<代码>数据()/代码>的返回值可以是任何(null或随机值)。这取决于编译器的实现。< /P> 在这种情况下,按照§17.3中的示例,您应该在使用

data()
之前调用
empty()
,以确保返回的值符合您的预期

if (!v.empty())
   do_something(v.data())

范围的约定是
[包含,排除)
,也就是说,如果您在范围上迭代
[X,Y)
,您将在概念上执行以下操作(伪代码):

这允许将空范围表示为
[X,X)
。此外,此空范围对于每个地址都定义得很好,无论其有效或无效

也就是说,
data()
的要求是(强调我的)

23.3.6.4[vector.data]

T*data()无异常

const T*data()const noexcept

返回:[data(),data()+size())为有效范围的指针 非空向量,data()==&front()


在我看来,唯一无条件的保证是
[data(),data()+size())
应该是一个有效的范围。对于
size()==0
成员函数
data()
可以返回任何值,并且范围将是有效的空范围。因此,如果
size()
为零,则允许实现返回非空指针。

是的,这是可能的,libstdc++正在这样做。 您可以查看


但是,可能不会指定对此指针执行操作,因为您正在访问向量中的未初始化范围,而不知道该范围(例如,您不知道内存束的确切大小)
为0,您的有效范围仍然为空。

如果向量为空(),则标准中的任何措辞都不建议数据()的给定值

下面是一些明确的证据,证明了为什么你不应该假设它可能是零,即使有时是零:

#include <vector>
#include <iostream>


void value_of_data(std::vector<int> const& v)
{
    std::cout << "empty() = " << v.empty() << ", " << "data() = " << static_cast<const void*>(v.data()) << std::endl;
}



int main()
{
    std::vector<int> v;
    value_of_data(v);

    v.resize(100, 0);
    v.clear();
    value_of_data(v);
}

范围是
[data(),data()+size())
[null,null)
是一个有效的空范围。另外,更新的GCC版本。@T.C.我同意,但是[same random address,same random address]也是一个有效的范围,并且可能vector::data()返回它吗?请注意,范围是半开的。如果“random address”是有效的,那么
[随机地址,相同的随机地址)
是一个有效的空范围。@在您的示例中,如果在调用
data()之前调用
vector::reserve(20)
,指针是非空的,而大小仍然是0.Re。在编辑时,没有任何说明它应该返回
nullptr
。它必须返回一个有效的范围,因此它可以返回
nullptr
,但不必返回。libstdc++这样做,并不自动意味着根据规范它是允许的。我同意我不应该这样做假设它为空,请注意,我在我的问题中也显示了类似的情况(只需构造一个零大小的向量)。但我更多的是要求对标准进行“确定”引用。这里指定了对象的状态-它为空。我不认为空范围
[c++,x,x ] < /c>在C++中可以被称为有效的任何代码> x <代码>。对于一个包含无效的地址而不是null的指针变量,你唯一可以做的事情就是覆盖它。很好,即使该地址不存在
T
。这就是
vector
能够合法地为空向量返回非空值的方式:该地址是有效的-它只指向“原始”内存,而不是
T
 data() _GLIBCXX_NOEXCEPT
 { return _M_data_ptr(this->_M_impl._M_start); }
#include <vector>
#include <iostream>


void value_of_data(std::vector<int> const& v)
{
    std::cout << "empty() = " << v.empty() << ", " << "data() = " << static_cast<const void*>(v.data()) << std::endl;
}



int main()
{
    std::vector<int> v;
    value_of_data(v);

    v.resize(100, 0);
    v.clear();
    value_of_data(v);
}
empty() = 1, data() = 0
empty() = 1, data() = 0x7ebc30