当我取消引用指针并将值分配给某个变量时,内存会发生啥?

Posted

技术标签:

【中文标题】当我取消引用指针并将值分配给某个变量时,内存会发生啥?【英文标题】:What happens to memory when I dereference a pointer and assign the value to some variable?当我取消引用指针并将值分配给某个变量时,内存会发生什么? 【发布时间】:2013-09-19 19:25:09 【问题描述】:

我有一个具有私有字符串指针的类。此类还有一个公共方法,该方法取消引用该字符串指针并将结果字符串返回给调用者。我的问题是:保存取消引用的字符串的内存会发生什么?

这是我的代码:

#include <iostream>
#include <string>

class myclass

    private:
        std::string *_name;

    public:
        myclass()
        
            this->_name = new std::string("my name");
        

        ~myclass()
        
            delete this->_name;
        

        std::string getName()
        
            return *this->_name;
        
;

void main()

    myclass m;
    
        std::string str = m.getName(); //what happens to this memory?
        std::cout << str << std::endl;
     //str deleted here (I think)
    //here, the m._name pointer hasn't yet been deleted

在我的主函数中,变量str 被分配了取消引用的字符串。保存这个字符串的内存会发生什么?我认为内存保留在堆栈上,因此当变量超出范围时会自动“取消分配”。令我困惑的是,即使取消引用的字符串不再在范围内,私有字符串指针仍可能在范围内。是否为 str 变量分配了私有 _name 指针值的副本?

如果这段代码确实在后台复制了字符串,我是否应该关注性能。如果我只是让getName() 返回_name 指针而不取消引用它,我的代码会运行得更快吗?

【问题讨论】:

它显然被复制了..如果您返回私有变量的地址,您将暴露它以被任何外部程序更改。我认为这不是您要在这里寻找的东西.. std::string getName() 正在返回一个字符串的副本。 str 值从_name 指向的字符串副本中复制值。更好的方法是将 getName() 定义为 const std::string&amp; getName() const return *(this-&gt;_name); 取消引用和解除分配是两件不同的事情:前者我们访问指针指向的内存位置,后者我们释放该特定变量的内存。 离题,但您可能不希望将指向字符串的指针作为成员。直接使用字符串。 @user2023861 getName() 没有释放任何东西,您在函数中取消引用字符串然后返回字符串的副本。然后将此副本再次复制到 str 中。返回带有 & 的字符串会导致它返回对 *_name 的引用而不进行复制,然后它将被复制到 str 中。它是const 的原因是为了不破坏封装。如果不是 const,您将可以直接访问 _name 指向的私有成员变量,这可能是您想要的,但它与您当前的 getName() 实现不同。 【参考方案1】:

首先,您不需要指针。其次,你可以返回一个副本(就像你做的那样)或一个引用(如果你想坚持的话,也可以返回一个指针),但是这两种方法都有利有弊:

class myclass

private:
    std::string _name;
public:
    myclass() : _name("my name")
    
    
    std::string getName1()  return _name; 
    std::string& getName2()  return _name; 
    const std::string& getName3() const  return _name; 

getName1 按值返回。缺点是会生成一个副本,这会影响性能,但在对象超出范围后返回值可以安全使用。

getName2getName3 的区别在于可以使用前者来修改类的实际成员。缺点是如果对象超出范围,则无法再使用该引用,因此您将留下一个悬空引用。优点是它更高效,因为不涉及复制。

myclass x;
std::string a = x.getName1(); // copy is made
std::string& b = x.getName2(); // no copy
                               // b is mutable
b = "something else";  //this will modify x._name
const std::string& c = x.getName3; // no copy
                                   // c is const

myclass* y = new myclass;
std::string d = x.getName1();  // copy is made
std::string& e = x.getName2(); // no copy
delete y;
d = "something else"; //legal
e = "something else"; //undefined behavior, e is a dangling reference

【讨论】:

如果我这样做std::string str2 = m-&gt;getName2();,(没有与号),str2 会是副本吗?在我的测试中,str2 似乎在delete y 之后仍然存在。 @user2023861 是的,它是副本。【参考方案2】:

遵循“三法则”。如果您定义了以下任何一个:复制构造函数、赋值运算符、析构函数,则定义所有这些。这样就不会混淆指向字符串的指针是否被删除:您只需在相应的赋值运算符中创建一个新的。

【讨论】:

以上是关于当我取消引用指针并将值分配给某个变量时,内存会发生啥?的主要内容,如果未能解决你的问题,请参考以下文章

当我们在 C 中取消引用 NULL 指针时,操作系统会发生啥?

引用与指针的区别

C++ 指针取消引用赋值

通过取消引用 NULL 指针来分配引用

为啥 uint8_t 在分配给取消引用的 uint32_t 指针时使用了 4 个字节?

当向量需要更多内存并分配内存时,指针会发生啥?