class Foo { public: Foo() { ::printf("default constructor\n"); } // "Rule of 3" for copyable objects ~Foo() { ::printf("destructor\n"); } Foo(const Foo&) { ::printf("copy constructor\n"); } Foo& operator=(const Foo&) { ::printf("copy assignment\n"); } }; Foo getFoo() { return Foo(); } int main() { Foo f = getFoo(); }
如果返回的对象不是可复制的,或者(N)RVO失败(可能不太可能发生),那么您可以尝试返回代理对象:
struct ObjectProxy { private: ObjectProxy() {} friend class Object; // Allow Object class to grab the resource. friend ObjectProxy f(); // Only f() can create instances of this class. }; class Object { public: Object() { ::printf("default constructor\n"); } ~Object() { ::printf("destructor\n"); } // copy functions undefined to prevent copies Object(const Object&); Object& operator=(const Object&); // but we can accept a proxy Object(const ObjectProxy&) { ::printf("proxy constructor\n"); // Grab resource from the ObjectProxy. } }; ObjectProxy f() { // Acquire large/complex resource like files // and store a reference to it in ObjectProxy. return ObjectProxy(); } int main() { Object o = f(); }
class Base {}; class Derived : public Base {}; // or boost::shared_ptr or any other smart pointer std::auto_ptr f() { return std::auto_ptr(new Derived); }
std::string f(bool cond = false) { std::string first("first"); std::string second("second"); // the function may return one of two named objects // depending on its argument. RVO might not be applied if(cond) return first; else return second; }
当然可以有一些旧的编译器,可以调用复制构造函数。 但你不应该担心现代编译器。
编译器是否可以应用RVO取决于所涉及的实际代码。 一般准则是尽可能晚地创建返回值。 例如:
std::string no_rvo(bool b) { std::string t = "true", f = "fals"; f += t[3]; // Imagine a "sufficiently smart compiler" couldn't delay initialization // for some reason, such not noticing only one object is required depending on some // condition. //return (b ? t : f); // or more verbosely: if (b) { return t; } return f; } std::string probably_rvo(bool b) { // Delay creation until the last possible moment; RVO still applies even though // this is superficially similar to no_rvo. if (b) { return "true"; } return "false"; }