【问题标题】:Modify pointer to std::string inside C++ class在 C++ 类中修改指向 std::string 的指针
【发布时间】:2014-05-02 08:40:55
【问题描述】:

我刚开始学习C++,一方面使用gnu 编译器,另一方面使用Visual C++Intel compiler,遇到了不一致。下面的例子定义了一个类Person,它带有一个指向std::string 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编译器则不可用?

【问题讨论】:

    标签: c++ class pointers


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 如果我想知道这个答案有什么不正确的地方。如果否决票有任何其他充分的理由,那么知道也很有用,因此我可以考虑在适当的情况下对其进行修复。
    • 正是我正在寻找的答案。谢谢。
    • n 不是临时的。这是一个局部变量。它有一个地址,并且没有任何关于存储该地址的不确定性。
    • @KerrekSB 好点,谢谢。我重新表述了答案。我希望现在更清楚了。
    【解决方案2】:

    该代码已完全损坏且无法使用。在Person::set 内部,n 是一个局部变量,所以它的地址&amp;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'; }
    };
    

    【讨论】:

    • 此举真的有必要吗?没有它们,优化编译器至少不会做类似的事情吗?
    • @rubenvb:我不认为任何东西都可以让编译器忽略重载解析的规则,不是吗?
    【解决方案3】:

    “更好的方法”并不是总是在类 C 语言中使用指针。触摸。

    即使你正确地传递了一个指向 set 的指针:

    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
    }
    

    【讨论】:

    • 谢谢,但我知道它存储在课堂之外。所以你的回答并没有真正回答我的问题。我只是想知道 n 在 set 方法中存在多长时间。
    猜你喜欢
    • 2016-02-19
    • 1970-01-01
    • 2019-12-17
    • 1970-01-01
    • 2012-04-19
    • 1970-01-01
    • 2012-11-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多