#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:
У вас есть ряд проблем в коде.
-
Отсутствует возврат в
operator<<
(как указано iammilind и другими), что вызывает ошибку времени выполнения, которую вы наблюдаете. Это можно исправить следующим образом:NameStream amp;operator <<(string name) { stream.push(name); return *this; }
-
Другая проблема связана с последовательностью вызовов в теле вашего цикла while, который:
- operator (int)
- оператор * ()
Поэтому на последней итерации вы сначала
pop()
входитеoperator (int)
, а затем пытаетесь вызватьfront()
inoperator*()
в пустой очереди, что вызовет ошибку времени выполнения.Самый простой способ исправить это — переписать цикл while следующим образом.
while (stream) { printf("%sn", (*stream).c_str()); stream; }
-
Утечка памяти. Вы вызываете выделение объекта NameStream с помощью
new
, но никогда не вызываетеdelete
. Простым решением является размещение вашего объекта stream в стеке:NameStream stream;
Комментарии:
1. Это, очевидно, тоже проблема (он не предоставляет правильную семантику для postfix
). Но его код не заходит так далеко; обратный просмотр стека показывает, что он не выполняется
operator<<
(несомненно, из-за пропущенного возврата). (На более высоком уровне это прекрасный пример злоупотребления перегрузкой оператора. Сопряжение<<
с.)
2. @Джеймс Канзе: Код OP может зайти так далеко, а может и не зайти, в зависимости от компилятора. В моем тесте (скомпилированном с g в режиме отладки) он передал operator<< нормально. Однако отсутствие возврата действительно является проблемой.
3. Код ОПЕРАЦИИ не зашел так далеко. Он опубликовал трассировку стека, показывающую сбой в
operator<<
. Действительно ли это происходит, зависит от того, как компилятор генерирует код; еслиostream
ссылка окажется в регистре, используемом для возвращаемых значений в концеoperator<<
, код может сработать. По-видимому, это было не так с его компилятором. (Интересная идея для режима отладки: при падении с конца поместите0xdeadbeaf
в регистр, используемый для возвращаемых значений.)