Question

I'm trying to implement a class, say Foo, which follows RAII, and objects of the class are returned to the client by value, i.e.

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

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

My immediate question would be is there any way to be sure that only one object of type Foo is constructed when calling SomeClass::getFoo()? I would think that most compilers know only one object need be constructed, but I know this is not guaranteed in most cases. Is there a better approach I can take?

I've tried returning a boost::shared_ptr<Foo> and just allocating a Foo object when constructing the shared pointer, and this works nicely. However, it does not seem ideal, as it requires heap allocation and makes for a less-clean interface.

Thanks!

Clarification

Visual Studio 2005 compiler so I don't think R-val references and C++11 related features are available.

Était-ce utile?

La solution

You've taken the best approach. The copy (or in fact move in C++11) will almost surely be elided by the compiler. In fact, even the copy from the return value to some object in the calling code will probably be elided too. So this will only call a single constructor:

Foo foo = sc.getFoo();

The rule that allows both of these copies (or moves) to be elided is:

when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move

Autres conseils

boost::optional + boost::in_place

If copy constructor is dangerous, it is better to disable it completely. Though most of compilers would elide copies in your case, some times it is possible to disable copy elision, for instance -fno-elide-constructors - and if code which "believes" in copy-elision would happen to run on such settings - there may be fireworks.

In C++98 you may use boost::optional + boost::in_place - there is no heap allocation, becuase boost::optional reserves enough place. And it is guaranteed that there will be no any copies.

live demo

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

Output is:

*
construction i=11
!

This code does work on MSVC2005.


Boost.Move

Another option is to use move semantic emulation for C++98 - Boost.Move. Copies are disabled:

live demo

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

Output is:

empty
empty
owner

This code also does work on MSVC2005.


C++11

In C++11 use following approach:

live demo

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 is created only once, it's copy and move constructor are deleted - it is guaranteed that there will be no any copies or moves.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top