C++ 中的 StringStream/c_str() 损坏

Posted

技术标签:

【中文标题】C++ 中的 StringStream/c_str() 损坏【英文标题】:StringStream/c_str() corruption in C++ 【发布时间】:2012-05-17 19:26:36 【问题描述】:

我遇到了一些关于 std::cout、std::stringstream 和 std::string.c_str() 的问题。主要是,似乎有些东西被困在某处的缓冲区中,我不知道如何解决这个问题。

如果你不喜欢阅读 *** 中的代码,这里是我的 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 字符串来处理某些事情。

任何帮助将不胜感激。

谢谢!

【问题讨论】:

只是想知道,使用appendoperator+/operator+= 进行连接有什么问题? 我在写的类中实现了operator+和operator+=;我认为用标准库对象重载运算符是不明智的。我还添加了一些其他功能。但是,我不知道附加。所以,这非常有用。 呸,我以为那个分支有所有的修复。在尝试解决这个问题时,我还注意到我正在返回对象的副本,而不是对同一对象的引用。实际定义为 Test& name(std::string);进行这些更改后,我一定没有添加和提交。我很抱歉。 【参考方案1】:

std::stringstream.str() 返回一个std::string 类型的临时对象。当TLStream::c_str() 返回时,此临时值超出范围,返回的char const* 指针指向已释放的内存。

【讨论】:

哦哦哦哦哦哦哦哦哦哦哦哦哦哦哦哦哦哦哦哦哦哦哦~迷人。我想我会完全放弃这种方法。在极少数情况下,我需要获取一个 c 字符串,我只需在 str() 方法的返回字符串对象上调用它,而不是尝试拉双重职责。【参考方案2】:
    std::cout << " => " << status[actual==expected] << std::endl;

== 将指向字符串文字"Exterminate"const char* 与指向str3.c_str()const char* 进行比较

那些指针是不同的。

您需要使用strcmp 之类的东西来比较它们,而不是通过指针相等。

【讨论】:

同样有效,但根据上述答案,我将完全删除该方法,因为只返回一个 c++ 字符串并在必要时调用 c_str() 方法更为优雅。跨度>

以上是关于C++ 中的 StringStream/c_str() 损坏的主要内容,如果未能解决你的问题,请参考以下文章

C++ 舍入算法中的 0.501,C++ 中的 Excel ROUND

使用 c# 中的 c++ 引用中的引用从 C# 错误调用 C++ 代码

Visual C++ 中的 C++ 代码库打开错误

C++:mwArray 作为 C++ 类中的变量

C++ 如何在 C++ 中覆盖文本文件中的数据?

C# 中的非托管 C++ 类