命名构造函数和临时生存期延长

Named constructors and temporary lifetime extension

本文关键字:生存期 构造函数      更新时间:2023-10-16

我正在寻找一种定义"基"构造函数的方法,该构造函数将使用默认值初始化值,然后将该基扩展到许多专用构造函数中。

我想要的伪代码可能看起来像:

class Foo{
private:
    int val;
    /* ... */
public:
    // Base constructor
    Foo(){ /*...*/ }           // This provides basic initialization of members
    // Named constructors
    static Foo fromString(string s){
        Foo f;                 // Call base constructor
        f.val = s.length();    // Customize base object
        return f;              // Return customized object
    }
    static Foo fromInt(int v){
        Foo f;
        f.val = v;
        return f;
    }
}

起初,我想延长临时f的生命周期,但 const 声明阻止我编辑其成员。 所以这似乎已经出来了。

然后我尝试了"命名构造函数"方法(如上所示)。 但是,我必须修改示例以首先创建对象,然后修改它,然后返回它。 这似乎有效,但我有理由相信这只是一个巧合,因为f是暂时的,并且在函数结束时超出了范围。

我也考虑过使用 auto_ptr s 之类的东西,但随后我同时使用 Foo 对象以及 Foo 的 auto_ptr s,这使得代码的其余部分"关心"对象是通过基构造函数(在这种情况下它将是一个对象)还是通过扩展构造函数之一(在这种情况下,它将是一个指针)创建的。

如果有帮助,在Python中,我会使用这样的东西:

class Foo(object):
    def __init__(self):
        /* Basic initialization */
    @classmethod
    def fromString(cls, s):
        f = Foo() #†
        f.val = len(s)
        return f

最后,我想这样做有两个原因:

  1. 代码重用,我想将通用初始化从每个构造函数中移出并移到一个构造函数中。 我意识到我可以通过每个构造函数调用的 init() 类型的私有方法来做到这一点,但我只想提到这一点。
  2. 清晰并解决歧义。 与命名构造函数示例的动机非常相似,参数类型本身不足以确定应使用哪个 ctor。 此外,fromSomething语法提供了出色的清晰度。

如果有一个简单的解决方案,请原谅我,在过去的几年里,我的工作已经从 c++ 转移到了 Java/Python,所以我有点生疏。

这是

完全有效的:

static Foo fromInt(int v){
    Foo f;
    f.val = v;
    return f;
}

当您返回f时,这将调用Foo 的复制构造函数(可能是编译器应用了返回值优化,因此不会创建任何副本)。 f超出了范围,但返回值只是它的副本,所以这是完全有效的,它工作不仅仅是"巧合"。

因此,如果您对使用命名构造函数方法的担忧只是您真的不知道它是否有效,请继续使用它,它非常有效。

在 C++11 中,您可以从构造函数调用其他构造函数:

struct X{
  X() : ... { ... }
  X(int i) : X() { ... }
  X(std::string s) : X() { ... }
};

对于 C++03,恕我直言,命名构造函数方法可能是最好且完全合理的。

为什么不:

class Foo{
private:
    int val;
    void Init(int v = <some default value>/*What ever here *));
    /* ... */

public:
    // Base constructor
    Foo(){ Init(); }           // This provides basic initialization of 
    Foo(string &s) { Init(s.length); };
    Foo(int v) { Init(v); };
};

似乎更简单。