views:

158

answers:

4

Hi, I'm starting to write a library and considering its interface. Previous libraries I've written all use raw pointers (both internally and in its interface), and now I want to try the smart pointer library that comes with VS2010.

  1. Should the interface use smart pointers? (Possibly forcing the library users to use smart pointers too?)
  2. Would it be messy if the interface uses raw pointers but the library uses smart pointers internally? (Is it even possible? shared_ptr doesn't have a release() method...)
  3. Can two c++0x compliant smart pointer libraries (say boost and VS2010) be used interchangeably? (say I use VS2010 to write my library and the users use boost)

Please help :)

A: 
  1. Depends on the whether you consider #2 or #3 more important.
  2. Yes.
  3. No, unless they were deliberately designed to.
dan04
A: 

I would say to use 80-20 rule here. If 80% of clients would be better of using boost/stl/C++ compliant, then please do so. For the rest, you can build adapter layer and move the complexity to that layer. The Adapter design pattern is my favourite for such purposes.

Chubsdad
+4  A: 

It is imposable to answer those question without understanding a lot more about your design principles and how you expect the library to be used.

So I can only answer based on my experience and how I like my libraries to be used.

  1. Yes.
  2. Yes. Don't do it.
  3. Its probably not a good idea to mix them (though I have never tried).
    But you can compensate for this:
    As most open source is distributed as source you can build your source so that it can be configured for use in many environments.

For Example:

#if   defined(MY_PROJ_SHARED_PTR_FROM_BOOST)

#include <boost/shared_ptr.hpp>
#define MY_PROJ_SHARED_PTR_NAMESPACE    boost

#elif defined(MY_PROJ_SHARED_PTR_FROM_STD)

#include <memory>
#define MY_PROJ_SHARED_PTR_NAMESPACE    std

#elif defined(MY_PROJ_SHARED_PTR_FROM_TR1)

#include <tr1/memory>
#define MY_PROJ_SHARED_PTR_NAMESPACE    std::tr1

#else
#error "MY_PROJ_SHARED_PTR_FROM_<XXX> not defined correctly"
#endif


namespace X
{
    using ::MY_PROJ_SHARED_PTR_NAMESPACE::shared_ptr;
}


int main()
{
    X::shared_ptr<int>  data;
}

I am sure there are other ways to do this.
But it is late.

Martin York
A: 

From a user's point a view I'd say that you just need to be clear in your interface about what you need.

Do you need a copy of the object or just a pointer?

Internally you can probably use the type of pointer that you're most convienant off as long as it don't degrade performance too much and don't cause bugs.

A question to ask is what exactly will you do with that pointer? Will you delete it? Can I change the reference if I update/delete the object (say in the case of a GUI library).

As someone who don't usually use smart pointers when they are not needed seeing too much smart pointers will just tell me you don't pay attention to what you will do and is cause for potential bugs.

As a library user I prefer a crash (when attempting to dereference a clearly invalid pointer) to having an semi-valid pointer around that is not actually what I expect (which I suspect can be a problem with using smart pointers of the shared_ptr kind).

n1ck
"As someone who don't usually use smart pointers when they are not needed seeing too much smart pointers will just tell me you don't pay attention to what you will do" Right. Can you tell me a situation where you shouldn't wrap a pointer up?
GMan
Can you tell me a situation when you should? Normally ownership is easily evaluated and a scoped_ptr is sufficient. Other pointers are just aliases and don't need any special pointers. I think that there might be situation where a shared_ptr is usefull but otherwise I'd throw the ball back at you and ask you why you want to use a shared_ptr yourself? I don't usually have that much problem to keep ownership of my pointers and know when I can or not delete it.
n1ck
@n1ck: Uh, every situation. I have a resource, I need to make sure it's released, both int he face of forgetfulness and exceptions. The only way to do that is in a destructor. Why *wouldn't* I? I'd want a shared pointer because I have a shared resource...and I don't want to care when it's freed, I just want to know it's going to be. The only situation I can think of is a non-owning pointer (which would be wrapped in some utility anyway, who's using the non-owning pointer for a purpose.)
GMan
@GMan. Well exception safety is a thing but 1. I don't think you need a shared_ptr for that (scoped_ptr should work) 2. I don't need my application to be that much exception safe anyway (most of the time any exception is a bug anyway)
n1ck
@GMan: "I'd want a shared pointer because I have a shared resource". The question is why do you have a shared resource. I don't usually need to share a resource that need to be shared without any clear ownership (ie a class that clearly own the pointer). In that case, yes, I think I'd say a shared_ptr would be appropriate but I think you overestimate the times you actually have a resource that you don't have a clear ownership.
n1ck
@GMan: and lastly: "and I don't want to care when it's freed". Why exactly don't you want to care when it's released? Working in a performance sensitive application I know I DO care when it's released as I will want to use the less memory possible. For me shared_ptr only make c++ looks like you're programming in .Net or something and do not provide clear advantages (see my comment about prefering a crash over having a valid pointer that is not what I expect in my answer) anyway.
n1ck
@n1ck: I'm confused at your moving the goal post. First you said "you don't need smart pointers when their not needed" and I said "when not?" and now you're somehow bringing up scoped_ptr versus shared_ptr. A scoped_ptr is a smart pointer too... And exceptions are a bug?! I think we're done here, you obviously don't know modern C++ or good coding practices. If you don't have to explicitly free something, your code is cleaner and safer. It's not like it kills you, and you can use them in a performance sensitive application; it's not like their slow. Your only objection seems to be...
GMan
..."I'm to good to use smart_ptr's, real programmers don't need that crap. We pretend like we are resource managing God's and laugh at exceptions and clean code."
GMan
@GMan : No the problem is that I prefer a crash to an invalid pointer. You don't need to attack me to get your lack of a point across thank you. I'll try to update my answer later to better explain what might be my concern with shared_ptr and your opinion will of course be welcomed.
n1ck
@n1ck: You said exceptions were a bug, they're a language feature. You said you don't need smart pointers and don't use them, I say that's bad practice. And then you start saying something about scoped pointer is fine, shared pointer isn't (totally off topic) and now something about crashing. I have no idea what you're talking about.
GMan
@GMan: Ok I'll clarify: yes exceptions are most usually indicating a bug. The only time I see an exception as not a bug would be in the case of a network failure or something where in this case this is really an exception. Other than that I don't use exception that much so what I meant was that an invalid index exception IS a bug. Please don't overblow what I say. If you want to argue about this I'm fine with it but don't try to act childish and pick my word for me.
n1ck
@GMan: Other than that I think you're pretty dead on : I don't use shared_ptr because, like I said, they lead more easily to invalid reference than a deleted pointer will. It will crash on dereference versus having a valid pointer but invalid element. Did you try to understand that sentence? I will try to post an exemple if you don't understand what I mean.
n1ck
@n1ck: You do realize exceptions are a useful language feature? Do you think `bad_alloc` is a bug? What is your definition of a bug? Also, how can you possibly have an invalid pointer with a shared pointer? If you still have a shared pointer to it, it won't be deleted.
GMan
@GMan: I think a common viewpoint is that, unless you develop very specific application, that if you get a bad_alloc exception you're in much more trouble anyway (to the point of it being treated as a bug) so why should you care about exception safety anyway.
n1ck
@GMan: concerning your second point I ask you if you really need me to post a code exemple as it will be time consuming. My point is that if you have an alias to a pointer that you delete, in the shared_ptr case the alias is still a live object that really exist even if it make no sense in the context where in the raw pointer case the alias is an invalid pointer that will crash on first use.
n1ck
@GMan: What I mean is that shared_ptr lack any sense of ownership and it do not seems to solve any problem to me. I have currently not found any smart_ptr that solved the invalid reference problem I'm talking about (it would need some kind of ref linking or something) automatically but my view is that shared_ptr is only usefull when you don't know the owner of the object (this could easily happen during refactoring, say). Most of the time, the owner is clear and you don't need any fancy shared_ptr.
n1ck
@n1ck: I didn't mean to talk about the practicality of `bad_alloc`. You said "most of the time any exception is a bug anyway", and I'm trying to give you an example of a standards required exception. Exceptions separate error handling from the code, and do a much better and easier job than error codes. Exceptions happen, and not because of bugs; because code is designed to use exceptions to indicate failures. And yes, please post an example. I don't see how the argument "delete that shared pointer manually and you broke it!" is worth anything: duh! You're not *suppose* to delete it,...
GMan
...that's the point of it being there. A shared pointer certainly doesn't lack any sense of ownership, how can you say that? The entire thing is a reference counter, the second (IME) most common type of ownership! You're calling a `shared_ptr` fancy, which it's not...it's just C++. In C++0x, it's standard. Just sounds like you've had a bad time using smart pointers correctly, and conclude they are bad because of it.
GMan
@GMan: "The entire thing is a reference counter, the second (IME) most common type of ownership!". Ownership as I intend it is not the way you keep track of your garbage collection (which is not possible to use in memory sensitive application like I develop). Normally objects own other object and outside of object I rarely use dynamic allocation but the scope could also be considered the owner. As long as it outlive your library call I am the owner of the object and you don't need to do any bookeeping about memory for me. That's all I'm saying.
n1ck
@GMan: Browsing the advertised questions on the side I just saw you (shared_ptr users) seems to be having problem with this pointer too (enable_shared_from_this - what is that stuff used for exactly?) as well as having to use weak pointer to somewhat keep track of your aliases anyway. So, if we forget our little fighting, I would like to ask you why you bother with shared_ptr at all since it seems a lot more trouble than it give you back. I could start a question about this but I would also be happy to hear your opinion about it if you care.
n1ck
@n1ck: I don't have any problems using shared_ptr. I follow the principle of separating resource usage from resource management, that it. A resource is bound in some form to an automatic variable, and I use that variable to access the resource. It makes the code cleaner, safer, and more elegant. That's it. If you're convinced managing things by hand is for you, that's fine. I don't care.
GMan
@GMan: I totally respect your position but I can't say I really agree with it. I think I will try to write that question if I get some time as I'm convinced that using shared_ptr everywhere is just wrong. My points are that 1. exception safety is not that much (and don't need a shared kind of special pointer). 2.It sure is usefull against memory leaks but can lead to other leaks (need to use weak_ptr which come back pretty much to managing it manually). 3. Manual memory management is not that hard anyway, only in special case (where I would probably have no objecting to the shared_ptr).
n1ck
@GMan: I think that you are right that the most automatic (scoped_ptr, deep_copy_ptr) it is the better but I think c++ is currently lacking (not even a deep_copy_ptr in boost!) and semi-manual managememt (I use deep_copy a lot) is the only way to go until we get better smart_ptr (for some use I could see some be relatively complex).
n1ck