开发者

Improper nesting of variable scopes in C++?

I have some code that looks something like this:

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

For the sake of argument, assume the default constructor for ComplexObject is costly.

  • Can (and do) C++ compilers replace the default construction/assignment of cpy with a copy constructor?
  • Is there any way to restructure the code so as to force that optimization while preserving the scope of both local objects?

Edit: I'm really looking for a general solution to the issue of wanting improper nesting of RAII objects with other things.

Any comments on this take on Konrad Rudolph's solution?

ComplexObject = LockedInitInPlace(obj->org, obj->开发者_如何学JAVA;mutex);

template<class C> C LockedInitInPlace(C& c, Mutex& m) {
    RAIILockObject _(m);
    return c;
}

Edit 2:

The origonal code has this sequence:

  1. Default construct cpy
  2. construct RAII lock
  3. assign (copy) existing object to cpy
  4. destruct lock
  5. use cpy
  6. destruct cpy

What I want is:

  1. construct RAII lock
  2. construct cpy (in this case by copy constructor using existing object).
  3. destruct lock
  4. use cpy
  5. destruct cpy


Unless the compiler can prove to itself that such optimization results in the same behavior then no. I can't really imagine a case where (given the mutex lock) the compiler could do this.

This may sound obvious, but can you change the default constructor to not be costly? Such constructors are likely to cause performance problems in other places if they're easily to accidentally invoke.

Alternately you're going to have to use the heap and pointers (via copy construct creation) rather than local instances.

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


It's quite unlikely that the default constructor would be avoided if the constructor is complex.

The compiler can do almost anything as long as the observable behaviour of your program remains intact.

The best way to solve this issue would be to not make the default constructor of ComplexObject expensive. It's bad practice to have expensive default constructors for this very reason.


Can (and do) C++ compilers replace the default construction/assignment of cpy with a copy constructor?

No, the compiler is forbidden from doing this (assuming that the default constructor of your class is complex enough that the compiler cannot prove that its elision will result in an equivalent program). Any compiler that does would not be standard conforming.

EDIT: The following solution is flawed! Do not use it!

The following solution hides a race condition. If your lock was to ensure that copying happened in a critical section then my “solution” will break this assumption since the copying may well (and probably will) happen outside this critical section. It only works if you are doing other work. But in your original code the mutex only makes sense if the copying itself is critical.

Just do the following to prevent default constructing:

ComplexObject = init(any_params_here);

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

Thanks to copy elision this won’t even perform unnecessary copies, just one (like in your code, but as a direct copy rather than copy assignment).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜