2016-10-19 4 views
1

У меня есть класс в C++, и я хотел бы иметь возможность печатать объект, поэтому я создал оператор char * cast. Дело в том, что по какой-то причине вывод операторной функции представляет собой случайные символы вместо возвращаемой строки. вот код:Случайный вывод с char * operator

operator const char*()const { 
    std::cout << (std::to_string(Nom) + '/' + std::to_string(Denom)).c_str() << std::endl; 
    return (std::to_string(Nom) + '/' + std::to_string(Denom)).c_str(); 
} 

и основная функция:

Rational r1(7, 15); 
std::cout << r1<<std::endl; 
return 0; 

Первый линейный выход нормально ("7/15"), но возвращаемое значение просто случайные буквы.

Любые подсказки?

+1

Как вы думаете, что делает c_str()? – UKMonkey

+3

Вы вызываете 'c_str()' на временный объект. Результат - обвисший указатель в тот момент, когда ваш оператор возвращается, даже раньше. – StoryTeller

+0

Причина, по которой 'std :: string' имеет' c_str() ', а не' operator char *() ', заключается в том, чтобы сделать ее более очевидной, так как такой код делает что-то серьезно неправильное. –

ответ

0

Дополнение к другим ответам: обычно неявный оператор литья является плохим стилем. Особенно приведение к типу, который не связан с вашим классом.

Если вы хотите, чтобы бросить свой объект, лучший способ может быть явное приведение:

class Rational 
{ 
public: 
    ... 
    std::string toString() const 
    { 
     return std::to_string(Nom) + '/' + std::to_string(Denom); 
    } 
}; 

Вы можете перегрузить «из» функцию с ним:

std::ostream & operator <<(std::ostream &stream, const Rational &obj) 
{ 
    stream << obj.toString(); 
    return stream; 
} 

Если вам нужно только вы можете использовать перегрузку без функции литья:

class Rational 
{ 
public: 
    ... 
    friend std::ostream & operator <<(std::ostream &stream, const Rational &obj) 
    { 
     stream << std::to_string(obj.Nom) + '/' + std::to_string(obj.Denom); 
     return stream; 
    } 
}; 
4

(std::to_string(Nom) + '/' + std::to_string(Denom)) создает временную переменную. .c_str() получает адрес некоторой памяти, принадлежащей этой переменной.

Вскоре после этого эта переменная уничтожается (вы не копируете/не перемещаете ее в любом месте). Память освобождается.

Адрес, полученный из c_str(), сохраняется, но теперь он указывает на некоторую память, которая может быть или не быть частью вашего приложения. Попытка прочитать это Undefined Behavior (или UB для краткости на этом сайте).

3

Замените объект, который управляет памятью, вместо необработанного const char*.

operator std::string() const { 
    std::stringstream ss; 
    ss << Nom << '/' << Denom; 
    return ss.str(); 
} 
+3

Если вам нужен оператор const char * (а не std :: string), тогда сохраните копию строки как члена класса, и вы можете вернуть ее .c_Str(). – UKMonkey

+0

Я бы предложил предложить строку 'mutable' member и добавить измененное« состояние измененное »bool, так что ленивая оценка и кэширование могут быть использованы без нарушения корректности' 'const' класса. Это позволяет помещать логику создания строки в оператор, так что фактическая репрезентативная строка будет генерироваться только при первом вызове оператора и обновляться только в том случае, если состояние экземпляра было изменено со времени последнего вызова. –