具有结构元素的 std::vector 的大小
我无法获得具有结构元素的向量的正确大小。元素类是这样定义的(我没有省略任何细节,尽管我认为唯一相关的事实是它是一个包含一个 int 和两个 double 的类):
class Interval
{
public:
Interval(int _i = 0, scalar _l = 0, scalar _r = 0) :
index(_i),
l(_l),
r(_r)
{ }
inline double left(void) const { return l; }
inline double right(void) const { return r; }
inline bool operator < (const Interval & i2) const { return left() < i2.left(); }
public:
int index;
double l;
double r;
};
然后在函数中我有这样的代码:
std::vector<Interval> arr(10);
int s1 = arr.size();
int s2 = arr.end() - arr.begin();
s1 的值我得到的是 15,而 s2 是正确的值 10。这是怎么回事? size() 不是应该准确返回元素的数量吗?它不是应该与 arr.end() - arr.begin() 相同吗?
任何回应和评论表示赞赏。
I'm having trouble getting the right size of a vector with struct elements. The element class is defined like this (I didn't omit any detail even though I think the only relevant fact is that it is a class containing an int and two doubles):
class Interval
{
public:
Interval(int _i = 0, scalar _l = 0, scalar _r = 0) :
index(_i),
l(_l),
r(_r)
{ }
inline double left(void) const { return l; }
inline double right(void) const { return r; }
inline bool operator < (const Interval & i2) const { return left() < i2.left(); }
public:
int index;
double l;
double r;
};
Then in a function I have this code:
std::vector<Interval> arr(10);
int s1 = arr.size();
int s2 = arr.end() - arr.begin();
The value of s1 I get is 15, while s2 is the correct value 10. What is going on? Isn't size() supposed to return exactly the number of elements? Isn't it supposed to be the same as arr.end() - arr.begin()?
Any response and comment is appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
首先在格式化代码时停止使用 HTML 标签。请改用 [代码] 按钮。
其次,你所描述的是一个无法解释的谜。您应该在
s1
和s2
中获得相同的值 -10
。除非您以某种方式设法破坏了其他代码中向量的完整性(即您运行的代码不是您向我们展示的代码)。Firstly stop using HTML tags when formatting the code. Use the [Code] button instead.
Secondly, what you describe is a mystery that defies any explanation. You should get the same value -
10
- in boths1
ands2
. That is unless you somehow managed to destroy the integrity of your vector in some other code (i.e. the code you run is not the code you show us).在键盘中按预期工作
Works as expected in Codepad
编辑:既然您已经提供了更多信息,也许我们可以对这种令人困惑的行为有所了解。
您违反了单一定义规则。这样做的结果并没有真正定义,但我们可以根据您观察到的结果做出一些有根据的猜测。
模板函数始终声明为内联,因为这是模板参数替换所必需的。当编译器遇到这些函数之一时,它可以选择将其作为内联代码发出或创建函数体并调用它。如果它创建一个函数体,则链接器将负责消除不同翻译单元中的重复定义。链接器不会做太多检查来查看明显的重复项在功能上是否等效,它只是根据函数的修饰名称进行检查,这取决于参数的类型;如果类型全部具有相同的名称,则假定它们是相同的。由于单一定义规则,它可以做出这一假设。
这就是源代码中未包含的类定义如何影响代码结果的原因 - 链接器将错误的代码副本替换为良好的代码副本。如果编译器生成内联代码,您将得到您期望的结果,如果链接器介入,您有 50/50 的机会得到错误的结果。即使你的代码很幸运,其他一些代码现在也会被破坏。
Original answer:
It is possible for a vector to be bigger than the requested size, but
size
won't reflect that value; you can test for this usingcapacity
. The excess storage will be part of the memory usage but the elements won't be initialized, and any attempt to access beyond the result ofsize
will result in undefined behavior.Edit: Now that you've provided more information, perhaps we can shed some light on this confusing behavior.
You've violated the One Definition Rule. The results of doing this aren't really defined, but we can make some educated guesses based on your observed results.
Template functions are always declared inline, as this is required for template parameter substitution. When the compiler encounters one of these functions, it has the choice of emitting it as inline code or creating a function body and calling it. If it creates a function body the linker becomes responsible for eliminating duplicate definitions in different translation units. The linker doesn't do much checking to see if the apparent duplicates are functionally equivalent, it just goes by the decorated name of the function, which depends on the types of the arguments; if the types all have the same names, they're assumed to be identical. It can make this assumption because of the One Definition Rule.
This is how you can have a class definition that isn't included in your source affect the outcome of your code - the linker is substituting a bad copy of the code for a good one. If the compiler generates inline code you'll get the outcome you expect, if the linker gets involved you have a 50/50 chance of getting the wrong thing. And even if your code gets lucky, some other piece of code is now whacked.
Original answer:
It is possible for a vector to be bigger than the requested size, but
size
won't reflect that value; you can test for this usingcapacity
. The excess storage will be part of the memory usage but the elements won't be initialized, and any attempt to access beyond the result ofsize
will result in undefined behavior.更新:在探索项目中的代码库之后,我在其他人编写的另一个标头中发现了另一个具有相同名称“Interval”的类(我不好选择这么简单的单词作为我的类名)。该类包含两个双精度数(在我的机器上为 16 个字节,而我的类有 24 个字节),这似乎解释了为什么 size() 调用返回的元素数量比实际数量多 50%。
但我不明白 std::vector 如何被这两个定义混淆(我没有在代码中包含该标头,但在包含该标头后我的标头可能包含在项目的其他部分中),并且end() - begin() 如何使用一个定义,而 size() 使用另一定义。
顺便说一句,为了避免在多程序员项目中发生此类冲突,最佳实践是使用命名空间,对吧?谢谢。
Update: After exploring the codebase in the project, I found another class with the same name "Interval" in another header written by other people (my bad to have picked such a simple word as my class name). That class contains two doubles (16 bytes on my machine, while my class has 24 bytes), which seemingly explains why the size() call returns 50% more than the actual number of elements.
But I don't understand how std::vector could be confused by the two definitions (I didn't include that header in my code, but my headers are probably included in other parts of the project after inclusion of that header), and how end() - begin() uses one definition while size() uses another definition.
Btw, to avoid such collisions in a multi-programmer project, the best practice would be to use namespaces, right? Thanks.