我有一些看起来像这样的代码:
ComplexObject cpy;
{
RAIILockObject _(obj->mutex);
cpy = obj->org;
}
// use cpy
为了论证,假设ComplexObject
的默认构造函数很昂贵。
编辑:我真的在寻找一个通用的解决方案来解决RAII对象与其他东西不正确嵌套的问题。
对Konrad Rudolph的解决方案有何评论?
ComplexObject = LockedInitInPlace(obj->org, obj->mutex);
template<class C> C LockedInitInPlace(C& c, Mutex& m) {
RAIILockObject _(m);
return c;
}
编辑2:
原始代码具有以下序列:
cpy
lock
cpy
lock
cpy
cpy
我想要的是:
lock
cpy
(在本例中是使用现有对象的复制构造函数)。lock
cpy
cpy
答案 0 :(得分:3)
除非编译器能够向自己证明这种优化导致相同的行为,否则不行。我无法想象编译器可以执行此操作的情况(给定互斥锁)。
这听起来很明显,但是你可以将默认构造函数更改为而不是代价高昂吗?如果这些构造函数容易被意外调用,则可能会在其他地方引起性能问题。
或者,您将不得不使用堆和指针(通过复制构造创建)而不是本地实例。
std::scoped_ptr<ComplexObject> cpyPtr = 0;
{
RIAALockObject _(obj->mutex);
cpyPtr = new ComplexObject(obj->org);
}
ComplexObject& cpy = *cpyPtr; // create alias for ease of use.
答案 1 :(得分:3)
如果构造函数很复杂,则不太可能避免使用默认构造函数。
只要程序的可观察行为保持不变,编译器就可以做任何事情。
解决此问题的最佳方法是不要使ComplexObject
的默认构造函数变得昂贵。由于这个原因,拥有昂贵的默认构造函数是不好的做法。
答案 2 :(得分:3)
可以(和做)C ++编译器用复制构造函数替换cpy的默认构造/赋值吗?
不,禁止编译器执行此操作(假设您的类的默认构造函数足够复杂,以至于编译器无法证明其省略将导致等效程序)。任何编译器都不符合标准。
编辑:以下解决方案存在缺陷!不要使用它!
以下解决方案隐藏了竞争条件。如果您的锁是为了确保在关键部分进行复制,那么我的“解决方案”将打破这一假设,因为复制可能(并且可能会)发生在外这个关键部分。如果您正在执行其他工作,则仅有效。但是在原始代码中,如果复制本身很重要,则互斥锁才有意义。
只需执行以下操作以防止默认构建:
ComplexObject = init(any_params_here);
ComplexObject init(any_params_here) {
RAIILockObject _(obj->mutex);
return obj->org;
}
感谢copy elision,这甚至不会执行不必要的副本,只需一个(就像在您的代码中一样,但是作为直接复制而不是复制分配)。