2012-05-17 3 views
0

У меня возникли проблемы с std :: cout, std :: stringstream и std :: string.c_str(). В основном, кажется, что есть вещи, которые где-то попадают в буфер, и я не уверен, как исправить эту проблему.StringStream/c_str() коррупция в C++

Если вы не любите читать код в StackOverflow, вот соответствующие ссылки на мой GitHub: TLString class, то Test class и the unit test - и вы можете пропустить до конца, где я сформулируем мой более краткий вопрос.

В моем модульном тестировании, у меня есть следующий код:

Test <std::string> strtest; // A unit test object expecting strings. 
    Test <const char*> chtest; // A unit test object expecting const char*s 
    // ... 

    TurnLeft::Utils::TLString str3("Exterminate."); 
    // ... 

    /* Basically, name() and expect() will use the passed arg. 
    * in the output in order to 
    * display output such as the following: 
    * str(): expecting 'Exterminate.' | Actual 'Exterminate.' => PASS 
    */ 
    strtest.name("str()").expect("Exterminate.").test(str3.str()); 

    /* To try and determine where the corruption was occuring, I did a 
    * simple cout here, and got what should be the expected result of 
    * the next test, 
    * meaning that the actual test should be succeeding. 
    */ 
    std::cout << str3.c_str() << std::endl //outputs Exterminate. normally. 

    /* But when I try to invoke that same method (c_str()) within the test 
    * object, it simply copies the argument passed in for name(). 
    */ 
    chtest.name("c_str()").expect("Exterminate.").test(str3.c_str()); 
    // Should output 'Exterminate.' as in the saatement before, but instead 
    // outputs 'c_str()'. 

Вот код класса Test:

namespace unittest{ 
static std::string status[2] = {"FAIL", "PASS"}; 

    template <class ExpectedResult> 
    class Test 
    { 
    private: 
     ExpectedResult expected; 
     ExpectedResult actual; 
     std::string  testName; 
    public: 
     Test(); 
     Test <ExpectedResult>& expect (ExpectedResult value); 
     Test <ExpectedResult>& name (std::string); 
     void test (ExpectedResult value); 
    }; 

template <class ExpectedResult> Test <ExpectedResult>& 
Test<ExpectedResult>::expect(ExpectedResult value) 
{  
    expected = value; 
    return *this; 
} 

template <class ExpectedResult> 
Test <ExpectedResult>& 
Test<ExpectedResult>::name(std::string aName) 
{ 
    testName = aName; 
    return *this; 
} 

    template <class ExpectedResult> 
    void Test<ExpectedResult>::test(ExpectedResult value) 
    { 
     actual = value; 
     std::cout << testName << ": "; 
     std::cout << "Expecting: " << expected << " | "; 
     std::cout << "Actual: " << actual; 
     std::cout << " => " << status[actual==expected] << std::endl; 
    } 

Класс TLString это один, что я пишу, что даст еще несколько операций с жидкостями для строк в C++ (например, конкатенация). Он использует строковый поток для обработки этих операций. Метод TLStream::c_str() действительно просто делает это: return stream.str().c_str();

Таким образом, я действительно путают о том, как actual в настоящее время присваивается значение testName. Я не уверен, где происходит конфликт, учитывая, что единственное время, когда те, к переменным, приближаются к взаимодействию, - это когда они выводятся в CLI и даже более похожи, поскольку в этом случае эти два являются разными типами данных.

Я написал в функции c_str(), потому что вы просто не знаете, когда какая-то сторонняя библиотека будет полагаться на строки C вместо строк C++ и не видит причин ограничивать мой класс. Даже в std :: ios вам нужно использовать строки c для некоторых вещей.

Любая помощь была бы принята с благодарностью.

Спасибо!

+0

Просто интересно, что не так с использованием 'append' или' operator +/operator + = 'для конкатенации? – chris

+0

Я реализую оператор + и оператор + = в классе, который я пишу; Я не счел целесообразным перегрузить оператора стандартным библиотечным объектом. Есть и другие функции, которые я добавляю. Однако я не знал о добавлении. Итак, это супер полезно. –

+0

Бах, я думал, что у ветки есть все исправления. Я также заметил, пытаясь решить этот пролив, что я возвращаю копию объекта, а не ссылку на тот же объект. Фактическое определение читает Test & name (std :: string); Я, должно быть, не добавил и не совершил эти изменения. Мои извинения. –

ответ

4

std::stringstream.str() возвращает временный объект типа std::string. Это временное значение выходит за пределы области, когда возвращается TLStream::c_str(), оставляя возвращаемый указатель char const*, указывающий на освобожденную память.

+0

oh hooohhhhhh. Захватывающий. Наверное, я просто приму этот метод.В редких случаях мне нужно получить строку c, я просто вызову ее на объект строки возврата из метода str() вместо того, чтобы пытаться выполнить двойную работу. –

0
std::cout << " => " << status[actual==expected] << std::endl; 

== Это сравнивает const char*, указывающие на строковый литерал "Exterminate" с const char* указывая на str3.c_str()

Эти указатели отличаются.

Вам нужно сравнить их, используя strcmp, а не по указателю равенства.

+0

Также верно, но в приведенном выше ответе я полностью удаляю этот метод, так как более элегантно просто возвращать строку C++ и вызывать метод c_str(), когда это необходимо. –