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

C++ std::string作为成员函数参数的奇怪行为,c++,object,compilation,member,undefined-behavior,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 = co

我有一门课:

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::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函数时:

MyClass *p = new MyClass();
p->setFilename1("first_string");
p->printFilename1();
p->setFilename2("second_string");
p->printFilename1();
void setFilename2(char* str))
    {
        filename2 = str;
    }
我得到了我期望的结果:

第一组字符串

第一组字符串

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

那么到底发生了什么?这与我所知道的C++有关。如果一个函数不引用相同的变量,并且彼此之间没有任何关系,那么它们如何影响另一个函数

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

编辑:您能给我解释一下为什么这段代码会这样运行吗

MyClass *p;
p->setFilename1("first_string");
p->printFilename1();
p->setFilename2("second_string");
p->printFilename1();
您从不为p指向的对象分配内存,因此在*p上调用的任何对象都将是未定义的行为

您从不为p指向的对象分配内存,因此在*p上调用的任何对象都将是未定义的行为

c_str()
返回指向
char
数组的指针,只要
std::string
未修改,该数组将保持有效;在您的例子中,您调用的
std::string
对象
c_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;
    }
}
class-MyClass
{
std::string filename1;
std::string filename2;
公众:
void setFilename1(std::string str)
{
filename1=str;
}
void setFilename2(std::string str))
{
filename2=str;
}
空函数()
{
//做事
}
void printFilename1()
{
std::cout
c_str()
返回指向
char
数组的指针,只要未修改
std::string
,该数组将保持有效;在您的情况下,调用
c_str()
std::string
对象将在方法返回后立即销毁(它是从字符串文本动态创建的临时对象),因此您有效地存储了指向已释放内存的指针。当您执行
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;
    }
}
class-MyClass
{
std::string filename1;
std::string filename2;
公众:
void setFilename1(std::string str)
{
filename1=str;
}
void setFilename2(std::string str))
{
filename2=str;
}
空函数()
{
//做事
}
void printFilename1()
{

例如,我认为这也是错误的

void setFilename1(char* str)
{
    std::string buf = str;
    filename1 = const_cast<char*>(buf.c_str())
}
void setFilename1(char*str)
{
std::string buf=str;
filename1=const_cast(buf.c_str())
}
因为“buf”已在范围外删除

这没关系

void setFilename1(std::string str)
{
    static std::string buf = str;
    filename1 = const_cast<char*>(buf.c_str())
}
void setFilename1(std::string str)
{
静态std::string buf=str;
filename1=const_cast(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;
class-MyClass
{
char*filename1;
char*filename2;
公众:
void setFilename1(std::string&str)
{
filename1=const_cast(str.c_str())
}
void setFilename2(std::string和str))
{
filename2=const_cast(str.c_str())
}
空函数()
{
//做事
}
void printFilename1()
{
std::coutprintFilename1();
删除p;

例如,我认为这也是错误的

void setFilename1(char* str)
{
    std::string buf = str;
    filename1 = const_cast<char*>(buf.c_str())
}
void setFilename1(char*str)
{
std::string buf=str;
filename1=const_cast(buf.c_str())
}
因为“buf”已在范围外删除

这没关系

void setFilename1(std::string str)
{
    static std::string buf = str;
    filename1 = const_cast<char*>(buf.c_str())
}
void setFilename1(std::string str)
{
静态std::string buf=str;
filename1=const_cast(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;
class-MyClass
{
char*filename1;
char*filename2;
公众:
void setFilename1(std::string&str)
{
filename1=const_cast(str.c_str())
}
void setFilename2(std::string和str))
{
filename2=const_cast(str.c_str())
}
空函数()
{
//做事
}
void printFilename1()
{
std::coutprintFilename1();
删除p;

No,这与您编写代码的方式不正确有关。您无法存储
c_str()返回的指针
。你的类应该有一个类型为
std::string
@CodyGray的成员,谢谢,这是一个很好的观点。但是如果你发表了评论,我怎么能接受你的答案呢?你能解释一下为什么我的代码现在的行为如此吗?我希望在p->setFilename1(“第一个字符串”)行之后会崩溃,因为我返回的引用不会指向“first_string”,这是一个临时对象