Возвращающийся итератор, кажется, делает его недействительным - PullRequest
3 голосов
/ 06 января 2012

Я возвращаю итератор из моего fnc после того, как я его использовал, и этот итератор в точке возврата точек к некоторому символу, но после того, как этот fnc возвращает его, возвращенный итератор больше не указывает на этот символ.Что я делаю неправильно?

typename std::string::const_iterator return_iterator(const std::string& line)
{
    auto beg = line.begin();  
/*here I'm moving this iterator and assing to it i.e.*/  
    beg = line.begin() + some_position;
    return beg;//at this point it points to a character
}  

void other_fnc(const std::string& line)
{
auto pos = return_iterator(line);//after this fnc returns pos points to some rubbish
}

Есть идеи?

Ответы [ 2 ]

1 голос
/ 06 января 2012

Поскольку код примера, который вы опубликовали, не компилируется (typename std::string::const_iterator должен быть просто std::string::const_iterator), и исправление этой ошибки позволяет коду работать как положено , я предполагаю, что фактический код немного отличается.

Для меня это звучит как случай, когда параметр std::string копируется по значению, а подсчет ссылок каким-то образом прерывается до получения доступа к const_iterator. Например, эта подпись:

std::string::const_iterator return_iterator(std::string line)
                                                   // ^ Notice: Not passing by
                                                   //           reference

передает строку по значению. Из-за COW копия является общей, но в тот момент, когда функция вызывает line.begin(), вызывается неконстантная функция-член строки std::string::begin(), что означает, что новая копия базовой строки обычно создано. Возвращаемое неконстантное значение iterator затем неявно преобразуется в const_iterator (совершенно правильное преобразование).

РЕДАКТИРОВАТЬ: Чтобы продемонстрировать мою точку зрения, взгляните на вывод следующей версии, которая была изменена для передачи параметра line в return_iterator() по значению:

#include <cassert>
#include <string>
#include <iostream>

std::string::const_iterator return_iterator(std::string line)
{
    std::string::const_iterator beg = line.begin();
    std::cout << "In return_iterator(), &(*line.begin()) is " << static_cast<const void *>(&*beg) << '\n';
/*here I'm moving this iterator and assing to it i.e.*/
    beg = line.begin() + 3;
    return beg;//at this point it points to a character
}

void other_fnc(const std::string& line)
{
    std::string::const_iterator pos = return_iterator(line);//after this fnc returns pos points to some rubbish
    std::cout << "In other_fnc(), &(*line.begin()) is " << static_cast<const void *>(&*line.begin()) << '\n';
    assert(*pos == line[3]);
}

int main()
{
    std::string line = "This is a test.";
    other_fnc(line);
}

http://codepad.org/K9yaWqWA

Утверждение теперь не выполняется. Также обратите внимание, что адреса *line.begin() отличаются.

0 голосов
/ 06 января 2012

Полагаю, что в реальном коде, вероятно, есть шаблоны (typename мусор), и, вероятно, они неправильно указаны в аргументе функции возвращаемого типа.

Следующий код работает как положено:

const int some_position = 2; 

template <typename T>
typename T::const_iterator return_iterator(const T& line)
{
     typename T::const_iterator beg = line.begin(); 
     beg = line.begin() + some_position;
     return beg;//at this point it points to a character
}  

void other_fnc(const std::string& line)
{
    std::string::const_iterator pos = return_iterator(line);
    std::cout << "character to 2: " << *pos << std::endl;
}

int main()
{
    std::string str = "Hello world";
    other_fnc(str);
}

Проверьте ваш код в соответствии с ним. Если вы занимаетесь чем-то другим, обновите ваш вопрос.

(PS: я избавился от auto C ++ 11, так как на данный момент у меня нет совместимого компилятора)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...