【问题标题】:Returning char* goes wrong, print it good, return it badly (c++)返回 char* 出错,打印好,返回不好(c++)
【发布时间】:2016-05-23 10:53:26
【问题描述】:

在这个函数中,我需要返回一个 char* 变量,在我返回它之前,我打印它并且它打印得很好。导致返回变量错误的变量发生了什么,为什么?

功能:

const char* NameErrorException::what() const throw()
{
     std::string str = "NameErrorException: name \'";
     str += _name;
     str += "\' is not defimed";
     std::cout << str.c_str()<< std::endl; //Prints good
     return str.c_str(); 
}

打印代码:

catch (std::exception& ex)
{
   //Prints something like "▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌♀·┘v♦"
    std::cout << ex.what() << std::endl;
}

(NameErrorException 继承自异常)

谢谢!

【问题讨论】:

  • 可能duplicate.
  • str 是一个局部变量,与所有局部变量一样,它将在方法结束时被收集。如果你在方法中返回一个有效的指针,如果它来自一个局部变量,它将在方法之外是无效的,除非你为它分配了空间。这也适用于像 c_str() 这样的返回指针,除非你有理由认为返回的指针不会在以后被销毁,这肯定不是你的情况。
  • 也许不一定是重复的,但肯定有这个问题的答案。

标签: c++ char return stdstring


【解决方案1】:

一旦你离开函数,你的字符串str 将被销毁。所以你返回的指针是无效的,因为它指向对象处理的内存。如果对象被销毁,它将再次释放此内存。

使str 成为异常的成员并在构造函数中对其进行初始化。 比你的what() 会返回一个有效的指针(只要异常对象是有效的)。

#include <string>
#include <iostream>

class NameErrorException : public std::exception
{
    std::string m_what;
public:
    NameErrorException(std::string name)
        :m_what("NameErrorException: name \'" + name + "\' is not defined")
    {
    }

    const char* what() const throw() override
    {
        return m_what.c_str();
    }
};


int main() 
{
    try
    {
        throw NameErrorException("TEST");
    }
    catch (std::exception& ex)
    {
        std::cout << ex.what() << std::endl;
    }
}

请看这里:http://coliru.stacked-crooked.com/a/878d5835db998300

【讨论】:

  • std::string 的构造会抛出异常。拥有可以在构造时抛出的异常类型不一定是一个好主意。结果可能是引发了意外的异常。
  • @Peter 您建议在哪里构造字符串? what()const。我同意这可能会导致问题,但如果 std::string 抛出,我还期待其他一些更严重的问题。
  • 实际上不是正确的问题。您需要决定的是需要抛出哪些异常,并相应地实现异常类型。如果(例如)std::bad_alloc 被抛出对调用者无关紧要,那么您可以构建一个字符串。如果调用者应该只捕获一个NameErrorException,那么请确保该类型不需要构造任何std::string - 或任何其他动态分配内存的类型(例如,包含一个字符数组)。
  • 这似乎有点牵强,但这是一种方式。
【解决方案2】:

string::c_str() 返回一个指向使用的内部存储器的指针。

您的 string 对象是一个局部变量,它在您的函数调用结束时被销毁,导致之后的内存访问无效。

您应该将strcpy 用于新生成的内存块,或者直接返回std::string 对象,这将是更安全的选择。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-06
    • 2010-09-28
    • 1970-01-01
    • 1970-01-01
    • 2011-10-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多