可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
According to the draft standard (23.3.6.4 vector data), data() points to the underlying array and [data(), data() + size())
must be a valid range:
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
But what if the vector is empty? When I construct a zero-size vector:
#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;
}
MSVC 2010 returns null, but on Linux (with GCC 4.2.1 and Intel 12.1) I get a non-null address.
Is vector::data()
allowed to or should it return null? Could an implementation, for example, do a default-size initial allocation and return a (non-null) pointer to it?
Edit: Several answers focus on the validity of an empty-range. I fully agree there.
I would really like to see a good reference or explanation for: Is it allowed to, must it return null or may it also return non-null?
回答1:
The convention for ranges is [inclusive, exclusive)
, that is if you iterate over a range [X,Y)
you will conceptually do the following (pseudo-code):
for( iterator ii = X; ii != Y; ++ii) {
...
}
This permits to express an empty range as [X,X)
. Also this empty range is perfectly well defined for each address, no matter if it is valid or invalid.
That said the requirements for data()
are (emphasis mine):
23.3.6.4 [vector.data]
T* data() noexcept;
const T* data() const noexcept;
Returns: A pointer such that [data(),data() + size()) is a valid range. For a
non-empty vector, data() == &front().
It seems to me that the only unconditional guarantee is that [data(),data() + size())
should be a valid range. For size() == 0
the member function data()
may return any value and the range will be a valid empty range. Therefore I would say that an implementation is allowed to return a non-null pointer if size()
is zero.
回答2:
None of the wording in the standard suggests a given value for data() if the vector is empty().
And here's some definitive proof of why you should not assume it might be zero, even though it sometimes is:
#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);
}
example output (gcc7.2, -O2, linux):
empty() = 1, data() = 0
empty() = 1, data() = 0x7ebc30
http://coliru.stacked-crooked.com/a/dd1d13200c8b9a3a
回答3:
Yes, this is possible, and libstdc++ is doing this.
You can have a look at the documentation of data() in libstdc++
data() _GLIBCXX_NOEXCEPT
{ return _M_data_ptr(this->_M_impl._M_start); }
However, performing actions on this pointer may not be specified, as you are accessing an non-initialized range within your vector, without its knowledge (e.g you don't know the exact size of the memory bunch). Also, as size()
is 0, your valid range is still empty.
回答4:
There is a state that an object can be valid but unspecified:
valid but unspecified state [§ 17.3]
an object state that is not specified except that the object’s
invariants are met and operations on the object behave as specified
for its type
[Example: If an object x of type std::vector is in a valid but
unspecified state, x.empty() can be called unconditionally, and
x.front() can be called only if x.empty() returns false. —end example]
Reading the C++ standard, the state of data()
is not specified when the vector is empty. So, the state is valid but unspecified state. Therefore, the returned value of data()
when the vector is empty can be anything (null or a random value). It depends on implementation of the compiler.
In this case, following the example in §17.3, you should call empty()
before using data()
to ensure that the returned value is as your expectation.
if (!v.empty())
do_something(v.data())