我有一堂课:

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 ++的了解相矛盾。如果一个函数不引用相同的变量并且彼此无关,那么如何影响另一个函数呢?

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

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

最佳答案

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

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

class MyClass
{
    std::string filename1;
    std::string filename2;
public:
    void setFilename1(std::string str)
    {
        filename1 = str;
    }
    void setFilename2(std::string str))
    {
        filename2 = str;
    }
    void function()
    {
      // do semthing
    }
    void printFilename1()
    {
      std::cout<<filename1<<std::endl;
    }
}

关于c++ - std::string作为成员函数的参数的奇怪行为,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35670822/

10-11 22:42
查看更多