修改指向C++类内部std::string的指针



我刚开始学习C++,但在使用gnu编译器和使用Visual C++Intel compiler时遇到了不一致。以下示例定义了一个类Person,该类具有指向std::字符串Name的指针。在方法Person::set中,字符串是按值分配的。我相信更好的方法是使用指针,但这不是问题所在。

#include <iostream>
#include <string>
class Person
{
   std::string *Name;
public:
   Person(std::string *n);  //Constructor
   void print();
   void set(std::string n);
};
Person::Person(std::string *n) : Name(n) //Implementation of Constructor
{
}
// This method prints data of person
void Person::print()
{
    std::cout << *Name << std::endl;
}

void Person::set(std::string n)
{
    Name = &n;
}
int main()
{
    std::string n("Me");
    std::string n2("You");
    Person Who(&n);
    Who.print();
    Who.set(n2);
    Who.print();

    return 0;
}

gnu编译器给出了如下结果,正如我所期望的:

Me
You

但是Visual C++Intel编译器导致了未定义的行为。我想问题出在Person::set中复制变量n的寿命上。为什么使用gnu编译器完成Person::set后仍然可用,而使用Visual C++Intel编译器则不可用?

您的Set方法正在设置未定义的行为,因为您正在获取局部变量的地址,然后在另一个范围中使用它:

void Person::set(std::string n)
{
    Name = &n; // n is a local variable
}

任何在Person::set之外取消引用Name的尝试,就像在Person::print()中所做的那样,都是未定义的行为。

您尝试的所有编译器的行为都与未定义的行为兼容,因为一切都是.

该代码已完全损坏且无法使用。在Person::set内部,n是一个局部变量,因此其地址&n在该函数之外没有意义。存储它是毫无意义的,以后使用它是未定义的行为。


以下是用现代C++编写类的正确方法:

class Person
{
   std::string Name;
public:
   explicit Person(std::string n) : Name(std::move(n)) { }
   void set(std::string n) { Name = std::move(n); }
   void print() const { std::cout << Name << 'n'; }
};

"更好的方法"不是总是在类C语言中使用指针。Touché。

即使您正确地将指针传递到集合:

void Person::set(std::string* n)
{
    Name = n; // Correctly saves
}

您不知道n何时会被释放,因为它存储在Person class外部。更好的方法是Person类中保留Name的副本,并通过引用传入新字符串:

class Person
{
   std::string Name;
public:
   Person(const std::string &n);  //Constructor
   void print();
   void set(const std::string &n);
};
Person::Person(const std::string &n) : Name(n) //Implementation of Constructor
{
}
void Person::set(const std::string &n)
{
    Name = n; // Person class keeps its own copy of n
}

相关内容

最新更新