2

我正在尝试实现一个Foo遵循 RAII 的类,例如,该类的对象按值返回给客户端,即

class SomeClass {
public:
  class Foo {
    public:
      ~Foo() { /* follow raii */ }
    private:
      friend class SomeClass;
      Foo() { /* follow raii */ }
  };

  Foo getFoo() { return Foo(); }
};

我的直接问题是有没有办法确保Foo在调用时只构造一个类型的对象SomeClass::getFoo()?我认为大多数编译器都知道只需要构造一个对象,但我知道在大多数情况下不能保证这一点。我可以采取更好的方法吗?

我尝试在构造共享指针时返回 aboost::shared_ptr<Foo>并仅分配一个Foo对象,这很好用。但是,它似乎并不理想,因为它需要堆分配并且导致接口不太干净。

谢谢!

澄清

Visual Studio 2005 编译器,所以我不认为 R-val 引用和 C++11 相关功能可用。

4

2 回答 2

2

你已经采取了最好的方法。编译器几乎肯定会忽略副本(或实际上是 C++11 中的移动)。事实上,即使是从返回值到调用代码中某个对象的复制也可能会被省略。所以这只会调用一个构造函数:

Foo foo = sc.getFoo();

允许省略这两个副本(或移动)的规则是:

当尚未绑定到引用 (12.2) 的临时类对象将被复制/移动到具有相同 cv-unqualified 类型的类对象时,可以通过将临时对象直接构造到目标中来省略复制/移动操作省略的复制/移动

于 2013-04-03T22:35:06.080 回答
1

boost::optional + boost::in_place

如果复制构造函数很危险,最好完全禁用它。尽管大多数编译器会在您的情况下省略副本,但有时可以禁用复制省略,例如-fno-elide-constructors - 如果“相信”复制省略的代码碰巧在这样的设置上运行 - 那里可能是烟花

在 C++98 中,您可以使用boost::optional + boost::in_place - 没有堆分配,因为 boost::optional 保留了足够的位置。并且保证不会有任何副本。

现场演示

#include <boost/utility/in_place_factory.hpp>
#include <boost/noncopyable.hpp>
#include <boost/optional.hpp>
#include <iostream>
#include <ostream>

using namespace boost;
using namespace std;

struct Foo: private noncopyable
{
    explicit Foo(int i)
    {
        cout << "construction i=" << i << endl;
    }
};

void make(optional<Foo> &foo)
{
    foo = in_place(11);
}

int main()
{
    optional<Foo> foo;
    cout << "*" << endl;
    make(foo);
    cout << "!" << endl;
}

输出是:

*
construction i=11
!

此代码确实适用于 MSVC2005。


Boost.Move

另一种选择是对 C++98 - Boost.Move使用移动语义仿真。副本被禁用:

现场演示

#include <boost/move/utility.hpp>
#include <iostream>
#include <ostream>

using namespace std;

class Movable
{
    BOOST_MOVABLE_BUT_NOT_COPYABLE(Movable)
    bool own_resource;
public:
    Movable()
        : own_resource(true)
    {}
    ~Movable()
    {
        cout << (own_resource ? "owner" : "empty") << endl;
    }
    Movable(BOOST_RV_REF(Movable) x)
        : own_resource(x.own_resource)
    {
        x.own_resource = false;
    }
    Movable& operator=(BOOST_RV_REF(Movable) x)
    {
        own_resource = x.own_resource;
        x.own_resource = false;
        return *this;
    }
};

Movable make()
{
    return Movable();
}

int main()
{
    Movable m = make();
}

输出是:

empty
empty
owner

此代码也适用于 MSVC2005。


C++11

在 C++11 中使用以下方法:

现场演示

struct Foo
{
   Foo(const Foo &)=delete;
   Foo(Foo &&)=delete;
   Foo &operator=(const Foo&)=delete;
   Foo &operator=(Foo &&)=delete;

   Foo(int){}
};

Foo create()
{
   //return Foo{0}; // ERROR: needs Foo(self &&)
   return {0};
}

int main()
{
   auto &&t=create();
}

Foo 只创建一次,它的复制和移动构造函数被删除 -保证不会有任何复制或移动。

于 2013-04-03T22:38:56.237 回答