我应该按值还是通过指针存储构造函数参数?

时间:2015-04-03 18:19:22

标签: c++

让我们说我正在编写一个可以在各种环境中重复使用的课程。它的构造函数接受我存储在成员变量中的用户定义类型。即使对于我知道复制便宜的对象,我也试图通过值或指针来判断参数是否更好。

// By value
class MyType
{
private:
    SomeUdt udt_;

public:
    MyType(SomeUdt udt) :
        udt_ {udt}
    {}

    // ...
};

VS

// By pointer
class MyType
{
private:
    std::shared_ptr<SomeUdt> udt_;

public:
    MyType(std::shared_ptr<SomeUdt> udt) :
        udt_ {udt}
    {}

    // ...
};

如果我通过(共享)指针接受它,那么我几乎肯定会强制客户端在堆上分配该对象。 (技术上他们可以在堆栈上分配并仍然向我发送一个指针,但这将使所有权和生命周期变得混乱。)

如果我按价值计算,那么我会删除他们管理实例的能力,例如客户是否希望SomeUdt成为单身人士。

哪种方法更好?

编辑:

此分析中还有其他一些有趣的观点。

首先,一位评论者提到,如果我用指针,那么我的私人数据就不是完全私有的。客户端可以访问我的成员对象。

另外,如果用户定义的类型需要是多态的并且有任何纯虚拟成员,那么我认为你别无选择,只能使用指针。

3 个答案:

答案 0 :(得分:2)

这两种方法有不同的语义:

  1. SomeUdt说“我想要SomeUdt的值。”

    在这种情况下,客户端代码可以生成它喜欢的值 - 可能来自临时对象,或自动分配或动态分配。这没关系,因为它不是重要的源对象,而是。提供值后,客户端MyType不会共享任何状态。

  2. std::shared_ptr<SomeUdt>说“我想共享动态分配的SomeUdt对象的所有权。”

    在这种情况下,客户端代码应该动态分配SomeUdt对象,使用shared_ptr管理其生命周期,然后与MyType共享该对象的所有权。提供对象后,客户端MyType将共享某些状态。

  3. 除非你有充分的理由不这样做,否则你应该更喜欢按值传递对象。价值语义和本地状态总是好事。仅当需要共享所有权语义时,才应使用shared_ptr

    请记住,如果SomeUdt类型是可移动的,那么执行效率会更高:

    MyType(SomeUdt udt) :
        udt_ {std::move(udt)}
    {}
    
      

    如果我按价值计算,那么我会删除他们管理实例的能力,例如客户是否希望SomeUdt成为单身人士。

    MyType如何存储其州是自己的事业。为什么客户端代码需要关注?它应该由MyType封装。

      

    另外,如果用户定义的类型需要是多态的并且有任何纯虚拟成员,那么我认为你别无选择,只能使用指针。

    如果你想要多态,那么你本身就不能要求对象的值,因为你不知道该值的类型是什么。在这种情况下,我建议采用SomeUdt&SomeUdt const&(假设SomeUdt是基类)。然后,这表示“我需要一个SomeUdt对象”,并且不会就该对象的创建方式发出任何请求。

    采用shared_ptr纯粹是为了共享动态分配对象的所有权。它假设共享对象。

答案 1 :(得分:0)

除非有其他好的理由,否则更喜欢这种方法:

// By value, using move
class MyType
{
private:
    SomeUdt udt_;

public:
    MyType(SomeUdt udt) :
        udt_ { std::move(udt) }
    {}

    // ...
};

答案 2 :(得分:0)

我认为如果您正在对数据进行修改操作,那么最好按值进行操作。 如果您的课程就像容器/读者一样,那么通过引用是理想的。