C std ::queue не хочет выполнять push()

#c

#c

Вопрос:

Это простой класс и простая тестовая функция:

 #include <queue>
#include <string>

namespace {
    using namespace std;
}

class NameStream {
    queue<string> stream;

public:
    string operator * () { return stream.front(); }
    NameStream amp;operator   (int) { stream.pop(); return *this; }
    NameStream amp;operator   () { stream.pop(); return *this; }
    NameStream amp;operator <<(string name) { stream.push(name); }

    operator bool() { return !stream.empty(); }
};

inline void nameStreamTest() {
    NameStream amp;stream = *new NameStream;

    stream << "hi" << "hey" << "hoy";

    while (stream) {
        printf("%sn", (*stream  ).c_str());
    }
}
  

Он попадает в

 NameStream amp;operator <<(string name) { stream.push(name); }
  

внутри процедуры push queue, вот стек за пределами моего кода:

 #0  0x000b5079 in std::deque<std::string, std::allocator<std::string> >::push_back at stl_deque.h:1055
#1  0x000b50f2 in std::queue<std::string, std::deque<std::string, std::allocator<std::string> > >::push at stl_queue.h:204
#2  0x000b511c in NameStream::operator<< at NameStream.h:24
#3  0x000b520f in nameStreamTest at NameStream.h:32
  

Мой опыт в этом случае терпит неудачу. Что я делаю не так?

P.S.:

 NameStream amp;stream = *new NameStream;
  

Используется для очистки местоположения

 stream
  

объект по адресу (смещение?) 0x7d (!), который вызывает такое же исключение.

Комментарии:

1. У вас return *this; в operator << порядке?

2. ДА. Он возвращает ссылку на self .

3. В качестве дополнительного совета: использование -Werror (или «рассматривать предупреждения как ошибки») очень помогает при такого рода ошибках.

4. Вы уверены, что хотите это сделать: NameStream amp;stream = *new NameStream; ? Хотя это допустимо для C , это довольно необычно, и в вашем конкретном случае вы, похоже, пропускаете NameStream ресурс (никогда не вызывается delete ). Если вы можете, используйте локальные переменные: NameStream stream; , и если вам нужно использовать динамическое распределение, избегайте скрывать его с помощью ссылки и, если возможно, инкапсулируйте ресурс в интеллектуальный указатель для обработки времени жизни.

Ответ №1:

Поместите оператор return в конец вашей функции.

 NameStream amp;operator <<(string name) { stream.push(name); return *this; }
  

Добавить: неполучение допустимой ссылки / значения (при необходимости) вызовет UB, а это вызовет скрытые сбои или плохое поведение, которые часто трудно отлаживать (как в вашем случае). Поэтому никогда не игнорируйте предупреждение компилятора, если оно генерирует какое-либо.

Комментарии:

1. @vitaut, я знаю, что код не выдает ошибку компиляции. Как предполагает @Heandel, пропуск return приведет к сбою во время выполнения или плохому поведению. Я указывал на то же самое

2. @vitaut Будет ли это? Одной из очевидных возможных причин сбоя является то, что operator<< вызывается с недопустимым указателем. Который был «возвращен» из предыдущего operator<< .

3. Извините, ребята. Забудьте, что я сказал. Это точно отвечает на то, что запрашивает OP. Я думаю, что чрезмерное потребление Гиннесса, наконец, привело к частичному повреждению мозга.

Ответ №2:

Происходит сбой, поскольку постфиксный оператор имеет более высокий приоритет, чем operator * , поэтому, когда выполняется последняя итерация цикла, вы сначала pop удаляетесь из очереди, а затем пытаетесь выполнить, front к какому времени очередь пуста. Чтобы решить эту проблему, самый простой способ — разбить ее на два оператора типа:

 while (stream) {
        printf("%sn", (*stream).c_str());
        stream  ;
    }
  

Ответ №3:

Он попадает в

 NameStream amp;operator <<(string name) { stream.push(name); } 
  

Вы не возвращаете *this … связывая operator<<() вызовы в цепочку, второй и третий вызовы не имеют действительного адреса объекта для работы.

Ответ №4:

У вас есть ряд проблем в коде.

  1. Отсутствует возврат в operator<< (как указано iammilind и другими), что вызывает ошибку времени выполнения, которую вы наблюдаете. Это можно исправить следующим образом:

     NameStream amp;operator <<(string name) { stream.push(name); return *this; }
      
  2. Другая проблема связана с последовательностью вызовов в теле вашего цикла while, который:

    1. operator (int)
    2. оператор * ()

    Поэтому на последней итерации вы сначала pop() входите operator (int) , а затем пытаетесь вызвать front() in operator*() в пустой очереди, что вызовет ошибку времени выполнения.

    Самый простой способ исправить это — переписать цикл while следующим образом.

     while (stream) {
      printf("%sn", (*stream).c_str());
        stream;
    }
      
  3. Утечка памяти. Вы вызываете выделение объекта NameStream с помощью new , но никогда не вызываете delete . Простым решением является размещение вашего объекта stream в стеке:

     NameStream stream;
      

Комментарии:

1. Это, очевидно, тоже проблема (он не предоставляет правильную семантику для postfix ). Но его код не заходит так далеко; обратный просмотр стека показывает, что он не выполняется operator<< (несомненно, из-за пропущенного возврата). (На более высоком уровне это прекрасный пример злоупотребления перегрузкой оператора. Сопряжение << с .)

2. @Джеймс Канзе: Код OP может зайти так далеко, а может и не зайти, в зависимости от компилятора. В моем тесте (скомпилированном с g в режиме отладки) он передал operator<< нормально. Однако отсутствие возврата действительно является проблемой.

3. Код ОПЕРАЦИИ не зашел так далеко. Он опубликовал трассировку стека, показывающую сбой в operator<< . Действительно ли это происходит, зависит от того, как компилятор генерирует код; если ostream ссылка окажется в регистре, используемом для возвращаемых значений в конце operator<< , код может сработать. По-видимому, это было не так с его компилятором. (Интересная идея для режима отладки: при падении с конца поместите 0xdeadbeaf в регистр, используемый для возвращаемых значений.)