views:

98

answers:

4

Hi everybody,

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.

+1  A: 

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 both s1 and s2. 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).

AndreyT
Thanks for the tip. I'll try to do it the right way next time.
fang
I know what I showed doesn't make any sense. What I'm asking for is basically some insight on what may be possibly messing things up. The second half of the code shown initializes a vector and immediately asks the size, so there's not much possibilities, not any I can think of. I need you experts' experience to know the right place to look at (like, have you seen similar problems before with other people, what were the answers, etc). I'm sure the final answer to this one is most likely a stupid one, but I'm stuck on myself.
fang
A: 

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 using capacity. 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 of size will result in undefined behavior.

Mark Ransom
Thanks, I understand the difference between capacity and size. I'm having trouble with size specifically.
fang
+1  A: 

Works as expected in Codepad

rlduffy
Thanks for the verification. I did that too, and as expected, the problem is not within the part of code I showed. As I said in the last comment, I'm looking for answers like what kind of mechanism in C++ could possibly allow other code interfere with code as simple as those I showed, because I can't think of any.
fang
A: 

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.

fang