tags:

views:

234

answers:

3

File a.hpp:

class a;
typedef boost::shared_ptr<a> aPtr

class a{
public:
    static aPtr CreateImp();
    virtual void Foo() = 0 ;
    ....
};

File aImp.hpp:

class aImp : public a{

    virtual void Foo();

};

File aImp.cpp:

aPtr a::CreateImp()
{
     return aPtr(new aImp());
}

void aImp::Foo(){}

The client must use CreateImp to get pointer to a, and can't use a other ways. What do you think about this implementation? What do you think about this kind of implementation?

+7  A: 

This looks like a normal implementation if the Factory Method design pattern. The return of boost::shared_ptr just makes life of the programmer using this API easier in terms of memory management and exception safety and guards against simple mistakes like calling the function and ignoring the return value.

Edit:

If this is the only implementation of the base class, then it might be that the author was aiming for pimpl idiom to hide the implementation details and/or reduce compile-time dependencies.

Nikolai N Fetissov
Oh, should have mentioned that there is only one implementation of a. This is not a factory class.
amitlicht
Yes, this was the intention.But is it ok to return a shared_ptr and not a raw pointer?
amitlicht
It depends. It's certainly better then returning a raw pointer (again - possibility of memory leak when return value is ignored), but *which* smart pointer to use depends on the context (unique ownership, shared ownership, etc.)
Nikolai N Fetissov
And folks, please state your reason if you downvote.
Nikolai N Fetissov
Is it even possible to return a scoped_ptr? it seems that it is the best to use the object as scoped_ptr, but i don't think a function can return scored_ptr object.
amitlicht
A function can return `std::auto_ptr`.
Nikolai N Fetissov
yes, i know. auto_ptr's seems very risky to me - someone can accidentally pass the auto_ptr to other function and than try to use it again after the function returns.
amitlicht
@eriks: no, `scoped_ptr` (as the name quite clearly says) is a smart pointer for objects that do not leave the scope, and retuning it would transfer ownership from the scope of the function to the scope of the caller. The real options would be `std::auto_ptr` and `unique_ptr` (either boost or the new standard)
David Rodríguez - dribeas
@Nikolai N Fetissov: I disagree, you would have to balance the possible loss of memory against the safety it adds. Most C++ developers should be storing pointers returned from functions directly into smart pointers anyway. By using `shared_ptr` as compared to `auto_ptr` or `unique_ptr` you are forcing your users to your decision.
David Rodríguez - dribeas
@David: yes, that's why I said it depends. One cannot tell without bigger context. And your answer is definitely good about the Pimpl.
Nikolai N Fetissov
+1  A: 

Looks like good encapsulation, although I don't actually see anything preventing a from being used otherwise. (For example, private constructor and friend class aImp).

No compile unit using class a will have any knowledge of the implementation details except for aImp.cpp itself. So changes to aImp.hpp won't induce recompiles across the project. This both speeds recompilation and prevents coupling, it's helps maintainability a lot.

OTOH, anything implemented in aImp.hpp now can't be inlined, so run-time performance may suffer some, unless your compiler has something akin to Visual C++ "Link-Time Code Generation" (which pretty much undoes any gain to build speed from encapsulation).

As far as the smart pointer is concerned, this depends on project coding standards (whether boost pointers are used everywhere, etc).

Ben Voigt
+2  A: 

If the intention is using the PIMPL idiom, then it is not the most idiomatic way. Inheritance is the second strongest coupling relationship in C++ and should be avoided if other solutions are available (i.e. composition).

Now, there might be other requirements that force the use of dynamic allocation, and/or the use of an specific type of smart pointer, but with the information you have presented I would implement the PIMPL idiom in the common way:

// .h
class a {
public:
   ~a(); // implement it in .cpp where a::impl is defined
   void op();   
private:
   class impl;
   std::auto_ptr<impl> pimpl;
};
// .cpp
class a::impl {
public:
   void op();
};
a::~a() {} 
void a::op() { pimpl->op(); }

The only (dis)advantage of using inheritance is that the runtime dispatch mechanism will call the implementation method for you, and you will not be required to implement the forwarding calls (a::op() in the example). On the other hand, you are paying the cost of the virtual dispatch mechanism in each and every operation, and limiting the use of your class to the heap (you cannot create an instance of a in the stack, you must call the factory function to create the object dynamically).

On the use of shared_ptr in the interface, I would try to avoid it (leave freedom of choice to your users) if possible. In this particular case, it seems as if the object is not really shared (the creator function creates an instance and returns a pointer, forgetting about it), so it would be better to have a smart pointer that allows for transfer of ownership (either std::auto_ptr, or the newer unique_ptr could do the trick), since the use of shared_ptr imposes that decision to your users.

(NOTE: removed it as the comment makes it useless)

David Rodríguez - dribeas
the destructor is virtual
amitlicht