Dieser führt nicht zu einem Compilerfehler, sondern zu einem Laufzeitfehler. Anstatt eine falsche Zeit zu messen, erhalten Sie eine Ausnahme, die möglicherweise auch akzeptabel ist.
Jeder Konstruktor, den Sie schützen möchten, benötigt ein Standardargument, für das set(guard)aufgerufen wird.
struct Guard {
Guard()
:guardflagp()
{ }
~Guard() {
assert(guardflagp && "Forgot to call guard?");
*guardflagp = 0;
}
void *set(Guard const *&guardflag) {
if(guardflagp) {
*guardflagp = 0;
}
guardflagp = &guardflag;
*guardflagp = this;
}
private:
Guard const **guardflagp;
};
class Foo {
public:
Foo(const char *arg1, Guard &&g = Guard())
:guard()
{ g.set(guard); }
~Foo() {
assert(!guard && "A Foo object cannot be temporary!");
}
private:
mutable Guard const *guard;
};
Die Eigenschaften sind:
Foo f() {
// OK (no temporary)
Foo f1("hello");
// may throw (may introduce a temporary on behalf of the compiler)
Foo f2 = "hello";
// may throw (introduces a temporary that may be optimized away
Foo f3 = Foo("hello");
// OK (no temporary)
Foo f4{"hello"};
// OK (no temporary)
Foo f = { "hello" };
// always throws
Foo("hello");
// OK (normal copy)
return f;
// may throw (may introduce a temporary on behalf of the compiler)
return "hello";
// OK (initialized temporary lives longer than its initializers)
return { "hello" };
}
int main() {
// OK (it's f that created the temporary in its body)
f();
// OK (normal copy)
Foo g1(f());
// OK (normal copy)
Foo g2 = f();
}
Der Fall f2, f3und die Rückkehr der "hello"nicht gewollt werden. Um ein Werfen zu verhindern, können Sie zulassen, dass die Quelle einer Kopie vorübergehend ist, indem Sie die Option " guardJetzt schützen" anstelle der Quelle der Kopie zurücksetzen . Jetzt sehen Sie auch, warum wir die obigen Zeiger verwendet haben - es ermöglicht uns, flexibel zu sein.
class Foo {
public:
Foo(const char *arg1, Guard &&g = Guard())
:guard()
{ g.set(guard); }
Foo(Foo &&other)
:guard(other.guard)
{
if(guard) {
guard->set(guard);
}
}
Foo(const Foo& other)
:guard(other.guard)
{
if(guard) {
guard->set(guard);
}
}
~Foo() {
assert(!guard && "A Foo object cannot be temporary!");
}
private:
mutable Guard const *guard;
};
Die Eigenschaften für f2, f3und return "hello"sind jetzt immer // OK.