std :: string的奇怪行为作为成员函数的参数

时间:2016-02-27 14:17:03

标签: c++ object compilation member undefined-behavior

我有一个班级:

class MyClass

{
    char *filename1;
    char *filename2;
public:
    void setFilename1(std::string str)
    {
        filename1 = const_cast<char*>(str.c_str())
    }
    void setFilename2(std::string str))
    {
        filename2 = const_cast<char*>(str.c_str())
    }
    void function()
    {
      // do semthing
    }
    void printFilename1()
    {
      std::cout<<filename1<<std::endl;
    }
}

这是我的主要功能:

MyClass *p = new MyClass();
p->setFilename1("first_string");
p->printFilename1();
p->setFilename2("second_string");
p->printFilename1();

输出对我来说非常惊讶:

  

first_string

     

second_string

我发誓我的函数MyClass :: setFilename2没有输入错误,我没有设置两次filename2变量。

我正在使用g ++编译器版本4.8.4。以下是我编写课程的方法:

g++ -g -O -Wall -fPIC -pthread -std=c++11 -Wno-deprecated-declarations -m64 -I/home/user/root-6.06.00/include -c myClass.cxx

现在,另一个惊喜:我改变了MyClass :: setFilename函数:

void setFilename2(char* str))
    {
        filename2 = str;
    }

我得到了我预期的输出:

  

first_string

     

first_string

执行函数MyClass :: function()不会改变任何字符串的值。

那是怎么回事?这与我对C ++的了解相矛盾。如果一个函数不引用相同的变量并且彼此无关,那么它如何对另一个函数产生影响?

我想它可能与编译器版本或某些编译器选项有关。但我不知道发生了什么。

编辑:您能否向我解释为什么这段代码的行为方式如此?

3 个答案:

答案 0 :(得分:4)

c_str()返回指向char数组的指针,只要std::string未被修改,该数组就会保持有效;在您的情况下,在您的方法返回后立即销毁您调用std::string的{​​{1}}对象(它是从字符串文字中即时创建的临时对象),因此您可以有效地存储指向已释放的内存的指针。当你执行c_str()时看到新值的事实只是分配器正在回收之前用于另一个字符串的内存位置这一事实的副作用;就标准而言,这一切都是未定义的行为(你可以预料到悲剧性的崩溃)。

正确的方法是将printFileName1直接存储在您的班级中,它会在std::string个实例的整个生命周期内正确管理自己的内存。

MyClass

答案 1 :(得分:0)

MyClass *p;
p->setFilename1("first_string");
p->printFilename1();
p->setFilename2("second_string");
p->printFilename1();

你永远不会为p指向的内容分配内存,所以你调用* p的任何东西都将是未定义的行为

答案 2 :(得分:0)

我认为这也是错误的例子。

void setFilename1(char* str)
{
    std::string buf = str;
    filename1 = const_cast<char*>(buf.c_str())
}

因为'buf'被删除了范围。

没关系。

void setFilename1(std::string str)
{
    static std::string buf = str;
    filename1 = const_cast<char*>(buf.c_str())
}

其他方法:

class MyClass
{
    char *filename1;
    char *filename2;
public:
    void setFilename1(std::string& str)
    {
        filename1 = const_cast<char*>(str.c_str())
    }
    void setFilename2(std::string& str))
    {
        filename2 = const_cast<char*>(str.c_str())
    }
    void function()
    {
      // do semthing
    }
    void printFilename1()
    {
      std::cout<<filename1<<std::endl;
    }
}

MyClass *p = new MyClass();
string str1 = "first_string";
p->setFilename1(str1);
p->printFilename1();
string str2 = "second_string";
p->setFilename2(str2);
p->printFilename1();
delete p;