лямбда: должен ли захват константной ссылки по ссылке давать неопределенное поведение? - PullRequest
4 голосов
/ 21 июля 2011

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

Что меня сбивает с толку, так это то, что это не вызывало сбой во время выполнения: в конце концов, разве это не должно быть неопределенным поведением, так как afaik есть свисающая ссылка?Более того, если смотреть на id в отладчике, он даже не выглядит как мусор, а просто как правильно сконструированная пустая строка.

Вот тестовый пример;это просто печатает пустую строку:

typedef std::vector< std::function< void() > > functions;

void AddFunction( const std::string& id, functions& funs )
{
  funs.push_back( [&id] ()
    {
        //the type of id is const std::string&, but there
        //is no object to reference. UB?
      std::cout << id << std::endl;
    } );
}

int main()
{
  functions funs;
  AddFunction( "id", funs );
  funs[ 0 ]();
}

Ответы [ 3 ]

4 голосов
/ 21 июля 2011

Неопределенное поведение означает, что нет требования, что должно произойти.Нет требования, чтобы он падал.На какую бы память ни указывали ваши висячие ссылки, нет причины, по которой не должен содержать что-то, похожее на пустую строку, и вполне вероятно, что деструктор string оставляет память в этом состоянии.

3 голосов
/ 21 июля 2011

Получение чего-либо по ссылке означает, что вы должны позаботиться о том, чтобы оно оставалось живым достаточно долго.Если вы этого не сделаете, программа может просто работать, но она может просто позвонить Domino's и заказать двойной пепперони.По крайней мере, в соответствии со стандартом.

2 голосов
/ 10 июня 2012

. , Литерал в вызове функции является строго временным для этого вызова и испаряется при возврате, поэтому мы обращаемся к временному - недостатку, часто обнаруживаемому компиляторами - просто не в этом случае.

typedef std::vector<std::function<void()> > functions;

void AddFunction(const std::string& id, functions& funs) {
    funs.push_back([&id] ()
    {
        //the type of id is const std::string&, but there
        //is no object to reference. UB?
            std::cout <<"id="<< id << std::endl;
        });
}

int emain() {
    functions funs;

    std::string ida("idA");
           // let idB be done by the tenporary literal below
    std::string idc("idC");

    AddFunction(ida, funs);
    AddFunction("idB", funs);
    AddFunction(idc, funs);
    funs[0]();
    //funs[1](); // uncomment this for (possibly) bizarre results   
    funs[2]();
    std::cout<<"emain exit"<<std::endl;
    return 0;
}

int main(int argc, char* argv[]){
    int iret = emain();
    return 0;
}
...