2009-12-06 69 views
1

说我有一个具有Initialize()方法的类型A的对象。 该方法接收对象B,这些对象保留为对象数据成员。 B对象在多个对象之间共享,因此A应该包含最初接收的B对象而不是其副本。通过引用或指针共享对象

class A 
    { 
     public: 
      bool Initialize(B?? b); 
     private: 
      B?? m_B;  
    } 

对象B必须存在。因此,我认为通过引用传递它,而不是传递指针,如果B为NULL,则失败Initialize()。

m_B的唯一代名词是指针B的类型(它不能作为B的引用,因为B的初始化并不是在A c-tor中完成的)。因此,初始化应该看起来像:

bool A::Initialize(B& b) 
{ 
    m_B = &b; 
    .... 
} 

这样可以吗?

UPD:

  1. 的代码是不是新的,我只是想 “修理” 的一些问题。 其实我不是在谈论一些具体的A和B类,而是关于在我的代码库中接近问题的一种方式。代码广泛传递指向B的指针,并在Initialize()中验证它是否为NULL。

  2. 将B传递给A的C-tor并不总是一个好的选择。还有其他参数传递给A,在A创建时不存在。因此,我不想将部分参数传递给A-tor,其余部分传递给A :: Initialize()。

  3. shared_ptr也可以是“NULL”,因此将它传递给A :: Initialize()与传递指向B的指针没有区别,在这方面,如果B是强制的,Initialize()dos的声明不会声明不。在我的情况下,我想通过参考B来表达它。

  4. 我们的代码目前并未使用boost。所以,虽然shared_ptr比只传递原始指针更好的解决方案,但我提出的解决方案可能被认为是不好的,但仍然是解决方案。

+2

你不应该有一个名为Initialize()的函数 - 你应该有一个构造函数。 – 2009-12-06 17:38:58

+0

您可以使用bcp将单个组件从boost中提取出来:http://www.boost.org/doc/libs/1_41_0/tools/bcp/bcp.html – 2009-12-06 18:58:35

回答

1

我会留指针。 这里引用只是发送错误信息。

不要使用引用的情况下为对象,当你计划采取指针对象 并保持或共享,在C++的引用是允许的东西像运算符重载 等 主要原因和拷贝构造函数工作用于用户定义的类型。 如果没有它们,将很难提供这种功能,其语法 与内置类型没有区别。

但在这种情况下,你并不是想模仿内置类型。 您正在通过指针和 通常使用的对象上操作,即使通过几个不同的指针共享。 因此应该明确说明

b为NULL,请务必使用assert(b)(或类似结构) 强制合同并停止无效的程序。 (我不会抛出异常 即使您忘记了C++中的异常问题,您是否打算在您的代码中捕获并处理此类异常?) 我也将这样的断言添加到所有使用的代码m_B 万一有人忘了打电话A::Initialize()

使用引用来确保指针不为空,可能会失火。 在大多数实现中,您可以从NULL或悬空指针 引用,而不会产生任何错误。 只有当您尝试使用此引用时,您的应用程序才会失败。 所以如果有人不小心让你B *pb等于NULL, 你可以拨打pa->Initialize(*pb)并没有任何反应。 除pa->m_B现在为NULL。

是否使用类似boost::shared_ptr的东西取决于您和您的内存策略 管理。 这是一个完全不相关的问题。

+1

对不起,我完全不同意。通过指针说“这可以是可选的”。建议您为null声明null意味着您需要记录这样一个事实,即该函数虽然接受了指针,但必须采用不能为null的指针。接受引用说“这不是可选的”;你的论点不使用引用,因为它可能是空的,恕我直言,最有可能成为你的问题,因为你的设计被破坏,因为你拿一个指针,你应该参考,你没有强制执行可选或必需的参数性质。 ;) – 2009-12-06 21:16:39

+0

放松,有时人们不同意你。 – 2009-12-07 07:38:35

+0

你说得对。 我真的不知道为什么我甚至会为此争论。 我说我的意见,提供了一些论据,它应该是它。 对于我以后的评论有些粗鲁和毫无意义,我很抱歉。我应该删除它们。 – 2009-12-07 18:35:23

0

我会用boost :: shared_ptr去。如果你使用引用,你可能不得不担心引用的范围,如果你使用一个普通的指针,你会遇到内存管理的麻烦。谁将删除B?

也许你只是反思一下你的计划:你真的需要分享这个对象还是一个B型的拷贝足够吗?如果B将被其他类更改并且这些更改需要被其他类所知,则需要一个shared_ptr。

+2

您如何知道它是动态分配的? – 2009-12-06 17:43:48

2

如果B是可选的,那么它可以表示为一个指针。如果需要B,那么它应该被表示为参考。

如果可能,尽量避免使用初始化方法的“两阶段构造”。如果不能在内部完成对A的处理,则需要将B视为可选项,并将其作为指针存储,并在任何您想要使用的地方进行测试。

如果你的初始化方法(或理想的构造函数)需要一个B,那么你应该把它作为参考传入。

这一切都假设你知道谁实际上拥有B;也许B拥有A的实例并将它们初始化为对其自身的引用,或者B可能拥有所有引用该实例B的A的实例。

如果A自己B的对象联合那么你应该使用类似boost :: shared_ptr的东西来明确共享所有权;假设B是动态分配新的。

+0

我不同意。你很困惑你如何将对象与他们的一生联系起来。两者都应该是明确的,都不需要关联。说它应该是一个指针,因为它是一个指针,可能会变成无效的是虚假的;所有东西都可以用地址(指针)表示,如果你不管理它的生命周期,所有东西都可能失效。在这种情况下,代码被赋予一个必须存在的对象的引用;所以请使用参考。在代码中,由于两阶段初始化,对象是可选的,所以使用一个可以是有效对象或null的指针。 – 2009-12-07 08:30:25

+0

嗯,现在,以前的评论已被删除,似乎我在跟自己说话...... – 2009-12-16 11:09:08

+0

对不起。我只是觉得我的评论的语气有些粗鲁,并且被删除了。也许太快了。 – 2009-12-16 17:00:07

0

我相信你应该使用构造函数而不是使用Initialize方法。

把B传递给A的C-tor并不总是 不错的选择。还有其他 参数传递给A,而不是 存在于A创建时。因此,我不想将 参数的一部分传递给A-torr,其余部分则通过 A :: Initialize()。

您是否听说过预构造?

这里是你可以做的,而不是什么一个例子:

class IsEmpty{}; 
class A 
{ 
    B *b_; 
    int *c_; 
    char *d_; 

    void Initialize(B *b) 
    { 
     b_ = b; 
     c_ = b_->Getc(); 
     d_ = b_->Getd(); 
    } 

public: 
    A(B *b) 
    : b_(0), c_(0), d_(0) 
    { 
     if(b == 0) throw IsEmpty(); 
     Initialize(b); 
    } 
}; 
1

传递B中引用说,B的寿命长于寿命(或时间去初始化)A的如果是这种情况下,你应该通过rerefence。在内部,您也可以将参考文件存储在Boost reference wrapper(但是这是提升,所以可能不是一个选项)。

如果您传递指针,并且您确定它们应该永远不为NULL(如果程序正确),那么请使用assertions而不是if-clause来检查该指针。

我也有时有你想要的szenario,通常使用你提出的解决方案。这是最简单的一个。

根据类的复杂性和设计,还可以使用state pattern的变体,其中描述“初始化”状态的状态对象是在初始化方法中构建的。在这种情况下,您可以将引用传递给状态对象的构造函数。这可能有点矫枉过正(C++中的状态模式有相当多的锅炉板,所以确保它值得),并且需要大量的重构,但它可能以某种方式帮助你。

0

如果可能的话,我肯定会避免使用引用作为类的成员。有一百万种方法可能会让你烦恼。如果你这样做,你应该使用初始化列表,但这是你应该避免像瘟疫一样的另一个功能。它适用于简单的情况,但它可能会导致严重的问题。