我刚开始学习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
}