размер 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()?

Любой ответ и комментарий приветствуется.


person fang    schedule 31.10.2010    source источник
comment
Неизвестно, что рабочая реализация вектора сделает это. Пожалуйста, покажите весь код, который вы используете, чтобы убедиться в этом.   -  person Marcelo Cantos    schedule 31.10.2010
comment
Да, size() должен быть равен end() - begin(); нам нужен лучший тестовый пример, чтобы понять, что происходит.   -  person    schedule 31.10.2010
comment
Не будь расплывчатым, будь тузом; научитесь писать правильный тест-кейс! sscce.org xs4all.nl/~weegen/eelis/iso-c++/testcase.xhtml tinyurl.com/so-hints   -  person    schedule 31.10.2010
comment
@Marcelo, спасибо, но проблема в том, что это весь мой код, который задействован. Приведенное выше определение класса является полным определением и единственным с именем Interval. Последний фрагмент кода является единственным содержимым функции. Что еще вы хотели бы увидеть? Конечно, в моем проекте есть и другие коды, но они никак не связаны с проблемой, насколько я могу себе представить, и я не могу дать вам все эти коды по понятным причинам.   -  person fang    schedule 31.10.2010
comment
@fang: Если вы никогда не используете значения s1 и s2, как вы узнаете, что они неверны?   -  person Marcelo Cantos    schedule 01.11.2010
comment
@Marcelo, конечно, через отладчик.   -  person fang    schedule 22.11.2010
comment
@fang: отладчик может лгать, особенно с оптимизированным кодом и особенно с переменными, которые никогда не используются. Является ли это причиной проблем здесь, я не знаю, но вы всегда должны использовать переменные, прежде чем верить, что они верны в отладчике.   -  person Marcelo Cantos    schedule 22.11.2010
comment
хм, я не использую оптимизацию при отладке здесь, и я никогда раньше не видел, чтобы отладчики лгали с неоптимизированными сборками, но это хороший момент. Являются ли показания отладчика ненадежными, даже если оптимизация не используется?   -  person fang    schedule 24.11.2010


Ответы (4)


Изменить. Теперь, когда вы предоставили больше информации, возможно, мы сможем пролить свет на это запутанное поведение.

Вы нарушили правило одного определения. Результаты этого на самом деле не определены, но мы можем сделать некоторые обоснованные предположения на основе ваших наблюдаемых результатов.

Шаблонные функции всегда объявляются встроенными, так как это требуется для подстановки параметров шаблона. Когда компилятор встречает одну из этих функций, у него есть выбор: создать ее как встроенный код или создать тело функции и вызвать ее. Если он создает тело функции, компоновщик берет на себя ответственность за устранение повторяющихся определений в разных единицах перевода. Компоновщик не делает много проверок, чтобы увидеть, являются ли очевидные дубликаты функционально эквивалентными, он просто идет по оформленному имени функции, которое зависит от типов аргументов; если все типы имеют одинаковые имена, предполагается, что они идентичны. Это предположение может быть сделано благодаря правилу одного определения.

Вот как вы можете иметь определение класса, которое не включено в ваш исходный код, влияет на результат вашего кода - компоновщик заменяет плохую копию кода на хорошую. Если компилятор генерирует встроенный код, вы получите ожидаемый результат, если компоновщик вмешивается, у вас есть шанс 50/50 получить неправильный результат. И даже если вашему коду повезет, какой-то другой фрагмент кода будет взломан.


Исходный ответ: вектор может быть больше запрошенного размера, но size не будет отражать это значение; вы можете проверить это, используя capacity. Избыточное хранилище будет частью использования памяти, но элементы не будут инициализированы, и любая попытка доступа за пределами результата size приведет к неопределенному поведению.

person Mark Ransom    schedule 31.10.2010
comment
Спасибо, я понимаю разницу между емкостью и размером. У меня проблемы с размером конкретно. - person fang; 31.10.2010
comment
Я изо всех сил пытаюсь понять, как код OP нарушает ODR или как этот ответ решает проблему. - person Marcelo Cantos; 22.11.2010
comment
@Marcelo, ОП оставил ответ с дополнительной информацией: stackoverflow.com/questions/4061818/ - person Mark Ransom; 22.11.2010

Во-первых, прекратите использовать теги HTML при форматировании кода. Вместо этого используйте кнопку [Код].

Во-вторых, то, что вы описываете, является загадкой, не поддающейся никакому объяснению. Вы должны получить одинаковое значение — 10 — как в s1, так и в s2. Это если вам каким-то образом не удалось разрушить целостность вашего вектора в каком-то другом коде (т.е. код, который вы запускаете, не является кодом, который вы нам показываете).

person AnT    schedule 31.10.2010
comment
Спасибо за чаевые. Я постараюсь сделать это правильно в следующий раз. - person fang; 31.10.2010
comment
Я знаю, что то, что я показал, не имеет никакого смысла. То, о чем я прошу, - это, по сути, некоторое понимание того, что, возможно, все испортит. Вторая половина показанного кода инициализирует вектор и сразу же запрашивает размер, поэтому возможностей не так много, я не могу придумать. Мне нужен ваш экспертный опыт, чтобы знать, на что нужно смотреть (например, сталкивались ли вы с подобными проблемами раньше у других людей, каковы были ответы и т. д.). Я уверен, что окончательный ответ на этот вопрос, скорее всего, глупый, но я застрял на себе. - person fang; 31.10.2010

Работает должным образом в Codepad.

person rlduffy    schedule 31.10.2010
comment
Спасибо за проверку. Я тоже так сделал, и, как и ожидалось, проблема не в той части кода, которую я показал. Как я сказал в последнем комментарии, я ищу ответы, например, какой механизм в C++ может позволить другому коду вмешиваться в такой простой код, как те, которые я показал, потому что я не могу придумать ни одного. - person fang; 31.10.2010

Обновление: изучив кодовую базу в проекте, я нашел другой класс с тем же именем «Интервал» в другом заголовке, написанном другими людьми (мне плохо, что я выбрал такое простое слово в качестве имени моего класса). Этот класс содержит два двойника (16 байт на моей машине, в то время как мой класс имеет 24 байта), что, по-видимому, объясняет, почему вызов size() возвращает на 50% больше, чем фактическое количество элементов.

Но я не понимаю, как std::vector можно спутать с двумя определениями (я не включил этот заголовок в свой код, но мои заголовки, вероятно, включены в другие части проекта после включения этого заголовка), и как end() - begin() использует одно определение, а size() использует другое определение.

Кстати, чтобы избежать таких коллизий в проекте с несколькими программистами, лучше всего использовать пространства имен, верно? Спасибо.

person fang    schedule 31.10.2010
comment
Спорный вопрос сейчас, но вы могли бы просто отредактировать свой вопрос. - person Marcelo Cantos; 23.11.2010
comment
@ Марсело, верно, спасибо за совет. Я видел пару человек, публикующих обновления через ответы на свои вопросы, поэтому я подумал, что это обычный способ сделать это. Никогда не думал, что смогу отредактировать оригинальный пост. - person fang; 24.11.2010
comment
Нет проблем. Мы все рождаемся невежественными. :-) - person Marcelo Cantos; 24.11.2010