C ++按值返回 - 指针内部会发生什么?

时间:2015-03-21 22:58:21

标签: c++ pointers memory memory-management operator-overloading

所以我有一些SegFaults,并想知道是否有人可以更深入地解释我这是如何工作的。

我有一个围绕数字变量的包装类,我正在尝试构建表达式的计算树。以下是示例代码:

class DoubleWrap{ 
public:
   static int id;
   DoubleWrap(double value){this->value = value;myid=++id;}
   double value;
   int myid;
   std::vector<DoubleWrap*> parents;
   DoubleWrap operator+(DoubleWrap& x){
      DoubleWrap result(this->value + x.value);
      setParents(*this,result);
      setParents(x,result);
      return result;
   }
   void setParents(DoubleWrap& parent,DoubleWrap& child){
      child.parents.push_back(&parent);
   }
   void printTree(){
      std::cout<< "[" << this->myid << "]-(";
      for (auto& elem: this->parents)
          std::cout<< elem->myid << "," << elem <<",";
      std::cout<<")"<<std::endl;
      for (auto& elem: this->parents)
          elem->printTree();
  }
}

我得到的问题是x = a + b + c + d这样的表达式;当我试图寻找x的父母时,它有2个父母,但父母[0] .parents [0]是零,例如由于某种原因,指向分配位置的指针不起作用或分配的内存被销毁?

我很感兴趣,如果有人可以告诉我一个解决方法以及为什么会这样。

举一个关于这段代码的例子:

DoubleWrap dw(12.6);
DoubleWrap dw2(12.5);
DoubleWrap dw3(12.4);
DoubleWrap dw4(12.3);
DoubleWrap a = dw + dw2 + dw3;
DoubleWrap b = a + dw+ dw2+ dw3 + dw4;
b.printTree();

我期待输出:

[10]-(9,0x13a4b50,4,0x7fff5bdb62f0,)
[9]-(8,0x13a4b00,3,0x7fff5bdb62c0,)
[8]-(7,0x13a49f0,2,0x7fff5bdb6290,)
[7]-(6,0x7fff5bdb6320,1,0x7fff5bdb6260,)
[6]-(5,0x13a4db0,3,0x7fff5bdb62c0,)
[5]-(1,0x7fff5bdb6260,2,0x7fff5bdb6290,)
[1]-()
[2]-()
[3]-()
[1]-()
[2]-()
[3]-()
[4]-()

但我得到的结果(通常在不同的运行中有所不同):

[10]-(9,0x7ffffd5e2f00,4,0x7ffffd5e2de0,)
[9]-(33,0x1c6da10,3,0x7ffffd5e2db0,)
Process finished with exit code 139

我的猜测是,运算符的返回实际上复制了DoubleWrap变量,因此父指针中的指针指向的值超出了范围而内存被释放了?

临时解决方案是通过引用返回,但问题是为什么并且有适当的解决方案?

PS:修复了我之前遇到的错误,这在setParents中是个错误。

2 个答案:

答案 0 :(得分:1)

您的问题是您正在向临时对象添加指向该向量的指针。

DoubleWrap a = dw + dw2 + dw3;

以上内容将首先调用dw.operator+(dw2)。这会创建一个临时对象,我们将其命名为temp。然后它会调用temp.operator+(dw3)。现在在operator+内,此setParents号调用temp作为parent。然后,您获取temp的地址(至少这是代码应该进行编译的内容)并将其添加到child的向量中。

现在,当operator+的调用返回时,temp被破坏,a中的向量包含指向不存在对象的指针。


您可以使用shared_ptr将元素存储在向量中来解决此问题。请注意,如果参考周期是可能的,您应该小心使用weak_ptr打破这些周期(我在下面的代码中没有包含实现)。这是最终代码的样子:

class DoubleWrap {
public:
   static int id;
   DoubleWrap(double value) : value(value), myid(++id) {}
   double value;
   int myid;
   std::vector<std::shared_ptr<DoubleWrap>> parents;
   DoubleWrap operator+(const DoubleWrap& x) const {
      DoubleWrap result(this->value + x.value);
      setParents(*this, result);
      setParents(x, result);
      return result;
   }
   static void setParents(const DoubleWrap& parent, DoubleWrap& child) {
      child.parents.push_back(std::make_shared<DoubleWrap>(parent)); // makes a copy of parent
   }
   void printTree() const {
      std::cout << "[" << this->myid << "]-(";
      for (const auto& elem: this->parents)
         std::cout << elem->myid << "," << elem.get() << ",";
      std::cout << ")" << std::endl;
      for (const auto& elem: this->parents)
         elem->printTree();
   }
};

int DoubleWrap::id = 0;

答案 1 :(得分:0)

您的代码:    DoubleWrap运算符+(DoubleWrap&amp; x){       DoubleWrap结果(this-&gt; value + x-&gt; value); 如果x是一个指向DoubleWrap类的指针,但你已经将x编码为DoubleWrap类对象而不是指针,那么你的代码是正确的 应该读 :    DoubleWrap运算符+(DoubleWrap&amp; x){       DoubleWrap结果(this-&gt; value + x.value);