如何禁止临时工

对于Foo一个class级,有没有办法不给它命名呢?

例如:

Foo("hi"); 

如果你给它一个名字,只允许它,如下所示?

 Foo my_foo("hi"); 

第一个的生命期只是陈述,第二个是封闭的块。 在我的用例中, Foo测量构造函数和析构函数之间的时间。 由于我从来没有提到局部variables,所以我经常忘记把它放进去,不小心改变了一生。 我想得到一个编译时错误,而不是。

另一个macros观解决scheme:

 #define Foo class Foo 

声明Foo("hi"); 扩展到class Foo("hi"); ,这是不合格的; 但是Foo a("hi")扩展到class Foo a("hi") ,这是正确的。

这具有与现有(正确)代码的源和二进制兼容的优点。 (这个说法并不完全正确 – 请参阅Johannes Schaub的评论和下面的讨论: “你怎么能知道它是与现有代码的源兼容?他的朋友包括他的头并且具有void f(){int Foo = 0;}而且,每一行定义了Foo类的成员函数都会失败:void class Foo :: bar(){}“

如何一点点黑客

 class Foo { public: Foo (const char*) {} }; void Foo (float); int main () { Foo ("hello"); // error class Foo a("hi"); // OK return 1; } 

使构造函数私有,但给这个类一个创build方法。

这不会导致编译器错误,而是运行时错误。 而不是测量一个错误的时间,你会得到一个可能被接受的例外。

任何你想要防范的构造函数都需要一个默认的参数set(guard)被调用。

 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; }; 

其特点是:

 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(); } 

f2f3"hello"的返回情况可能不需要。 为了防止投掷,你可以让副本的来源成为临时的,通过重置guard来保护我们而不是副本的来源。 现在你也明白了为什么我们使用了上面的指针 – 它允许我们变得灵活。

 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; }; 

f2f3return "hello"的特性现在总是// OK

几年前,我为GNU C ++编译器写了一个补丁 ,为这种情况添加了一个新的警告选项。 这是在Bugzilla项目跟踪。

不幸的是,海湾合作委员会Bugzilla是一个墓地,考虑到补丁包含的functionbuild议去死。 🙂

这是由于希望在代码中使用本地对象作为locking和解锁的小工具,测量执行时间等等,来准确捕捉这个问题的主题。

因为在你的实现中,你不能这样做,但是你可以使用这个规则来获得你的优势:

临时对象不能绑定到非const引用

您可以将代码从类移动到一个独立的函数,它采用非const引用参数。 如果这样做,如果临时尝试绑定到非const引用,则会出现编译器错误。

代码示例

 class Foo { public: Foo(const char* ){} friend void InitMethod(Foo& obj); }; void InitMethod(Foo& obj){} int main() { Foo myVar("InitMe"); InitMethod(myVar); //Works InitMethod("InitMe"); //Does not work return 0; } 

产量

 prog.cpp: In function 'int main()': prog.cpp:13: error: invalid initialization of non-const reference of type 'Foo&' from a temporary of type 'const char*' prog.cpp:7: error: in passing argument 1 of 'void InitMethod(Foo&)' 

简单地说,没有默认构造函数,并且需要在每个构造函数中引用一个实例。

 #include <iostream> using namespace std; enum SelfRef { selfRef }; struct S { S( SelfRef, S const & ) {} }; int main() { S a( selfRef, a ); } 

不,恐怕这是不可能的。 但是你可以通过创build一个macros来获得同样的效果。

 #define FOO(x) Foo _foo(x) 

有了这个,你可以写FOO(x)而不是Foo my_foo(x)。

由于主要目标是防止错误,请考虑这一点:

 struct Foo { Foo( const char* ) { /* ... */ } }; enum { Foo }; int main() { struct Foo foo( "hi" ); // OK struct Foo( "hi" ); // fail Foo foo( "hi" ); // fail Foo( "hi" ); // fail } 

这样,你不能忘记命名variables,你不能忘记写struct 。 详细,但安全。

声明一个参数的构造函数是明确的,没有人会无意中创build该类的对象。

例如

 class Foo { public: explicit Foo(const char*); }; void fun(const Foo&); 

只能用这种方式

 void g() { Foo a("text"); fun(a); } 

但从来没有这样(通过临时堆栈)

 void g() { fun("text"); } 

另见:Alexandrescu,C ++编码标准,第40项。