如何限制构造寿命更长的对象所需的变量范围?

How to limit scope of variable needed to construct object that lives longer?

我在堆栈上有一个对象,它的构造函数需要另一个对象,如下所示:

{
    ObjectDef def(importantData);  // should die as soon as obj is created
    def.setOptionalData(100);

    Object obj(def);  // should live for the remainder of the function body
}

理想情况下,我喜欢将 def 这样的变量放在它们自己的范围内。这给了我名字 "def" ,并清楚地表明它不再有用了。

例如,这里用 result 发生了什么我想用 obj:

// scope block
{
    int result = complexFunction() + anotherFunction();
    printf("the result is %i", result);
    doMoreThingsWithIt(result); 
}
// "result" is now gone

但问题是,我可以看到,这里无法做到这一点。 Object obj 的构造函数不能在作用域之前,因为它的构造函数需要 def,而且它不能在作用域内,因为 obj 需要比 def 生存得更久。

有没有办法将 def 的范围限制在比 obj 更短的范围内,或者我是否应该接受它必须至少在范围内保持一样长的时间?

你可以使用 lambda:

Object obj{[&]{ ObjectDef def{importantData}; def.setOptionalData(100); return def; }()};

如果 ObjectDef 经常需要它的可选数据集并且这是一种常见模式,请考虑向 ObjectDef 添加一个构造函数以允许设置可选数据或创建一个命名的辅助函数来执行lambda 在这里完成的工作。

类似的东西:

Object obj;
{
    ObjectDef def(importantData);  // should die as soon as obj is created
    def.setOptionalData(100);

    obj = Object(def);
}

我越想越觉得你需要一个工厂function/method。如果这是您唯一需要的对象,lambda 方法可以正常工作,但如果您需要捕获可选参数或在多个地方使用 lamda,它可能会变得……混乱。

我的建议是在 Object(或者可能是一个新的 ObjectFactory class)上定义一个全局函数或一个静态方法,它将接受 importaintInfo 和一些额外的选项,并且 return 你完全构造的对象实例。这样你的 ObjectDef 永远不会比构造 Object 的时间长。

不过,我真的质疑对指针和堆分配的厌恶,了解为什么需要这么快销毁 ObjectDef 会很有帮助。我假设它要么具有锁定资源的句柄,要么是安全关键的,要么您正在为具有少量堆栈内存的系统编程。否则,快速销毁它的好处似乎会被调用工厂方法和为此类方法添加代码的开销所抵消。

I have an object on the stack that requires another object for it's constructor.

如果一个对象的构造需要多个步骤,为它创建一个工厂函数,并认为它是类型的一部分API.

这是 API 设计要遵循的一个很好的规则:

  • 当您编写客户端代码时,它从一开始就是干净的(并且复制粘贴不会为实例化创建重复代码)

  • 实例化代码变得可测试和可模拟;

  • 如果您需要另一组步骤来实例化一个 Object,您只需在第一个附近创建另一个工厂函数(自然地集中将此类型实例化到同一个源文件中的方法) .

  • 这将允许您将 Object 的实例化代码中的任何额外依赖项隐藏到定义 Object 方法的 .cpp 文件中(例如,节省您从必须 #include <ObjectDef.hpp> 在客户端代码中)。

您的客户端代码应始终需要一行来实例化对象:

auto make_object(Data &importantData, int optional = some_default)
{
    ObjectDef def(importantData);  // should die as soon as obj is created
    def.setOptionalData(optional);

    return Object{ std::move(def) }; // def dies here
}

客户代码:

auto obj = make_object(data); // about as short as calling a constructor
auto def = 0; // "def" identifier is free