c ++对象成员引用完整性:引用vs指针和valgrind不一致

时间:2014-05-24 17:33:55

标签: c++ pointers reference valgrind

假设我想创建一个对象,该对象引用某个其他类的对象 a A

参考与指针

我知道 a 应该在我的新对象的生命周期内持续存在,所以我首选的方法可能是使用新对象中的引用引用 a ,传递它在建设中。

但是,也可以选择将 a 表示为新对象中的指针。这有点灵活,但是对于与参考明确的关系失去了一些东西。

在下面的代码中,类 R 使用引用引用 A ,而类 P 使用指针。

#include <iostream>

class A
{
  int val; // A toy class that stores an int!                                                                                                                
public:
  A(int val_) : val(val_){}
  ~A(){}
  void dump() const { std::cout << val << std::endl; }
};

class R
{ 
  const A & a; // Represent the association with 'a' as a reference                                                                                          
public:
  R(const A & a_) : a(a_){}
  ~R(){}
  void dump() const { a.dump(); }
};

class P
{ 
  const A * a; // Represent the association with 'a' as a pointer                                                                                            
public:
  P(const A * a_) : a(a_){}
  ~P(){}
  void dump() const { a->dump(); }
};

R manufactureR(int val)
{ 
  A a(val);
  R r(a);
  r.dump();
  return r; // Pull the rug out from under 'r' as 'a' drops out of scope.                                                                                    
}

P manufactureP(int val)
{ 
  A *a = new A(val);
  P p(a);
  p.dump();
  delete a; // Pull the rug out from under 'p' by deleting 'a'.                                                                                              
  return p;
}

int main()
{ 
  // Reference version: This code is dodgy, but valgrind doesn't moan                                                                                        
  R r = manufactureR(3);
  r.dump();

  // Pointer version: This code is dodgy and valgrind rightly moans                                                                                          
  P p = manufactureP(3);
  p.dump();

  return 0;
}

Valgrind和捕捉错误

如上所述,我的偏好是当我知道引用不需要更改时引用我的对象成员,并且引用的对象将在我的对象的生命周期中持续存在。

无论哪种方式,如果在新对象存在期间 a 由于编码错误而丢失/破坏,那么显然很糟糕,但新对象继续提及它。

但可以说更糟糕的是无法发现错误何时发生。

最后的代码创建 R P 中的每一个的实例,然后通过销毁引用的/指向对象来故意破坏它们。

我得到的输出是这些:

$./test
3
1726372352
3
0

有趣的是,当发生不幸事件并且引用的对象消失时,valgrind并没有像我期望的那样报告错误。在释放 a 后,它会在指针版本中发现无效读取大小4

如果通过使用引用,存在错误导致我无意中读取死记忆的风险,并且valgrind无法检测到它,那么它足以让我使用指针。

问题

有没有其他人观察/遭受过valgrind的这种不一致,或者因为我是C ++的新手(来自C的长期职业生涯),在尝试使用引用作为对象成员时,我误解了一些基本的东西?也许这个例子是有缺陷的,因为我在 manufactureR 的回归中依赖于RVO,有效地复制(没有赋值) r 中的引用。

详情

CentOS 6.5; gcc version 4.7.2 20121015 (Red Hat 4.7.2-5) (GCC); valgrind-3.8.1

0 个答案:

没有答案