假设我有以下内容:
#include <memory>
struct A { int x; };
class B {
B(int x, std::unique_ptr<A> a);
};
class C : public B {
C(std::unique_ptr<A> a) : B(a->x, std::move(a)) {}
};
如果我正确理解了关于"C++函数参数未指定顺序"的规则,那么这段代码是不安全的。如果使用移动构造函数先构造B
的构造函数的第二个参数,则a
现在包含一个nullptr
,并且表达式a->x
将触发未定义行为(很可能是段错误)。如果先构造第一个参数,则一切都会按预期工作。
如果这是一个普通的函数调用,我们可以创建一个临时变量:
auto x = a->x
B b{x, std::move(a)};
但是在类的初始化列表中,我们没有自由创建临时变量。
假设我不能改变 B
,那么有没有可能实现上述操作?也就是在同一个函数调用表达式中取消引用并移动一个 unique_ptr
,而不创建临时变量?
如果您能更改 B
的构造函数,但不能添加新方法(例如 setX(int)
),那会有帮助吗?
谢谢
B
的构造函数,则无需执行任何操作。只需使用单个参数unique_ptr<A>
,并在构造函数的初始化列表中复制a->x
即可。 - PraetorianB
的接口来支持此特定用法。使用a->x
初始化x
可能不是一件预期的事情,因此不应该需要来自B
的特殊情况。这取决于上下文,但对于仅采用unique_ptr
的构造函数,将x
初始化为某个默认常量可能更自然,而不是a->x
。如果我们将B
更改为通过右值引用获取unique_ptr
,我们可以免费为调用者提供更多灵活性,而不更改接口。我不认为在这里传递unique_ptr
参数的原因。 - Matthew FioravanteB
构造函数,并添加一个只接受unique_ptr<A>
的重载版本。在这种情况下,暗示着B
将从a->x
初始化x
。你选择哪一个取决于类的预期用途。 - Praetorian