c++中变量范围嵌套不当



我有一些代码看起来像这样:

ComplexObject cpy;
{
  RAIILockObject _(obj->mutex);
  cpy = obj->org;
}
// use cpy

为了便于讨论,假设ComplexObject的默认构造函数是昂贵的。

    c++编译器可以(并且可以)用复制构造函数替换copy的默认构造/赋值吗?是否有任何方法重构代码,以便强制优化,同时保留两个局部对象的作用域?

编辑:我真的在寻找一个通用的解决方案,以希望RAII对象与其他东西嵌套不当的问题。

对Konrad Rudolph的解决方案有什么评论吗?

ComplexObject = LockedInitInPlace(obj->org, obj->mutex);
template<class C> C LockedInitInPlace(C& c, Mutex& m) {
    RAIILockObject _(m);
    return c;
}

编辑2:

原始代码有这样的序列:

  1. 默认结构cpy
  2. construct RAII lock
  3. 分配(复制)现有对象给cpy
  4. 销毁lock
  5. 使用cpy
  6. 销毁cpy

我要的是:

  1. construct RAII lock
  2. 构建cpy(在这种情况下,通过使用现有对象的复制构造函数)。销毁lock
  3. 使用cpy
  4. 销毁cpy

除非编译器可以向自己证明这种优化会导致相同的行为,否则不会。我真的无法想象(给定互斥锁)编译器可以做到这一点。

这可能听起来很明显,但是您可以将默认构造函数更改为而不是吗?如果这样的构造函数很容易被意外调用,则很可能在其他地方导致性能问题。

或者你将不得不使用堆和指针(通过复制构造创建)而不是本地实例。

std::scoped_ptr<ComplexObject> cpyPtr = 0;
{
  RIAALockObject _(obj->mutex);
  cpyPtr = new ComplexObject(obj->org);
}
ComplexObject& cpy = *cpyPtr;  // create alias for ease of use.

如果构造函数很复杂,则不太可能避免使用默认构造函数。

编译器可以做几乎任何事情,只要你的程序的可观察行为保持不变。

解决此问题的最佳方法是不要使ComplexObject的默认构造函数昂贵。由于这个原因,使用昂贵的默认构造函数是不好的做法。

c++编译器可以(并且可以)用复制构造函数替换copy的默认构造/赋值吗?

不,编译器被禁止这样做(假设你的类的默认构造函数足够复杂,以至于编译器无法证明省略它会产生一个等效的程序)。任何这样做的编译器都不符合标准。

编辑:下面的解决方案是有缺陷的!不要使用它!

下面的解决方案隐藏了一个竞争条件。如果你的锁是为了确保复制发生在临界区,那么我的"解决方案"将打破这个假设,因为复制很可能(而且很可能)发生在这个临界区之外。只有当你在做其他工作时,才会起作用。但是在原始代码中,互斥锁只有在复制本身是关键的情况下才有意义。

只需执行以下操作以防止默认构造:

ComplexObject = init(any_params_here);
ComplexObject init(any_params_here) {
    RAIILockObject _(obj->mutex);
    return obj->org;
}

由于复制省略,这甚至不会执行不必要的复制,只需一个(就像在您的代码中一样,但作为直接复制而不是复制赋值)。

相关内容

  • 没有找到相关文章

最新更新