3

For a piece of multiplatform c++ code I am writing, I need a shared pointer. Currently the project does not use boost, and pulling it in would be extremely difficult or impossible from an administrative view. However, I can use select C++11 features, including shared pointers.

There is a problem with the standard shared pointers, they guarantee thread safety. That means that on some platforms/compilers, like GCC ( http://tinyurl.com/GCCSharedPtrLockPolicy ) atomics and mutexes will be needlessly used, but at least I can check and work around issues incurred by this. Then for other platforms ( http://tinyurl.com/msvscSharedPtr ) there does not even appear to be a way to check, what thread safety mechanisms are used. The original boost pointer provides only the most basic of thread safety guarantees ( http://tinyurl.com/SharedPtrThreadSafety ).

My core issue here is that on some platforms Atomics can cause costly synchronizations between CPU caches and unneeded Mutexes can cause calls to the OS that that may delay for not entirely related reasons. This code will be multi-threaded, but we have other synchronization methods for moving data between threads. A thread-safe shared pointer is simply not needed or wanted.

Normally, I would prefer to benchmark and make my decision, but because of the platforms this will run on, and be ported too, I cannot practically do so. I would need to test on some of the less popular platforms, where less optimized compilers tend to exist, but I do not have that ability currently.

I will try to make a push to get Boost pointers, but that is unlikely, what are my other options for when that fails? In the mean time I will research trying to get just the Shared_ptr out of boost, but I do not think that will be easy.

I could roll my own. This seems like a terrible idea, why would I have to re-invent something this basic.

If there is a library with that is simple and has liberal enough licensing, then I could simply copy their shared_ptr code and simplify rolling my own.

Edit: Pulling in anything from boost other than header only libraries has been struck out. I will be researching Loki as one of the answerers suggested. If that fails and no answers materialize here, I will roll my own :( .

Sqeaky
  • 1,876
  • 3
  • 21
  • 40
  • 8
    I never buy the “administrative overhead” argument for Boost. The whole focus of these libraries was to make them easily available, they have got extremely permissive licenses, installing Boost nowadays is a single command on all major platforms, and all of the header-only libraries (including SharedPtr) can just be dropped into an `include` folder without *any* installation. I cannot think of a technically justified, compelling argument where using Boost would provide *any* kind of hurdles. – Konrad Rudolph Mar 20 '12 at 18:24
  • 3
    Mutexes will only be used on platforms with no built-in atomic operations, which are pretty close to non-existing. Atomic operations are not terribly expensive and are probably not worth the effort of avoiding. Odds are you've got them all over the place, starting with your memory allocator, your I/O functions, and so on. – David Schwartz Mar 20 '12 at 18:25
  • 1
    Strictly for the record `boost::shared_ptr` has been providing the same thread-safety guarantees as those of `std::shared_ptr` for some time already now, so that doesn't fit the OP's needs. There's `boost::intrusive_ptr` though. – Luc Danton Mar 20 '12 at 18:25
  • Do you really need shared pointers if the reference counting overhead is too much for you? Is it the case that you want to share pointers (which isn't the same as saying you need to use shared pointers)? – James Mar 20 '12 at 18:27
  • 3
    This question is based on assumptions that make no sense. What is the cost that you want to avoid by avoiding the thread safety? For `shared_ptr` that are not *shared* (the pointer, not the pointee) by different threads, on access you do not check the reference count. Only copying/destructing `shared_ptr`s access the memory that is *shared* among threads. – David Rodríguez - dribeas Mar 20 '12 at 18:34
  • I do need the semantics of shared ownership, but as inexpensively as I can get it. How are the thread safety guarantees the same? I was under the impression boost provided none as per linked docs, and in practice the std shared pointers used mutexs/atomics. Unless the boost docs are wrong. – Sqeaky Mar 20 '12 at 18:39
  • I was under the impression that it would take more than just `dropping in a header file`. If that is the case, this will be easy. If I will have to build boost and bring their jam build system in then that will most likely get shot down. I am still researching – Sqeaky Mar 20 '12 at 18:40
  • 3
    @Sqeaky: The boost docs have a section on thread safety, and the guarantees are shown there. – David Rodríguez - dribeas Mar 20 '12 at 18:42
  • 1
    @Sqeaky : Note that unlike `std::shared_ptr<>`, you can disable thread safety in `boost::shared_ptr<>`; from the docs: "*If your program is single-threaded and does not link to any libraries that might have used shared_ptr in its default configuration, you can `#define` the macro `BOOST_SP_DISABLE_THREADS` on a project-wide basis to switch to ordinary non-atomic reference count updates.*" – ildjarn Mar 20 '12 at 20:18
  • 1
    Why do so many people feel that shared_ptr's must be shared across threads? There are plenty of situations where an object must persist through the lifetime of other objects, and it is not known which object will go away last. – Sqeaky Mar 21 '12 at 03:19
  • @DavidRodríguez-dribeas in the boost Docs I linked it says "shared_ptr objects offer the same level of thread safety as built-in types." That sounds like it is not thread safe in terms of using a special syncing mechanism. As far as my 'assumptions' not making sense, please see the GCC docs, which I linked above 'If only one thread of execution exists in the program then less expensive non-atomic operations are used.' It seems pretty clear that if I don't need it I shouldn't pay for it – Sqeaky Mar 21 '12 at 03:25
  • @KonradRudolph The Shared Pointer part of boost is not header only, and on top of that it has at least 13 includes of other boost items, and at least 2 associated source files. I have not been able to get the boost pointer included and I find your choice not to 'buy it' in reference to real administrative overhead very rude. I am flagging your comment as not constructive. Not all programmers have the final say about what is or isn't included in what they code, and your comments deliberately ignore that. – Sqeaky Mar 21 '12 at 03:28
  • 1
    @Sqeaky: ... Take the time to read the whole paragraph and since you are at it, the whole section that contains basically a couple of examples and a few lines underneath. If you don't understand exactly what that means, it means that it has exactly the same thread guarantees than `std::shared_ptr`. You might not have understood what those guarantees are or where they affect your code, but they are the same. To be able to provide the same guarantees that *raw* pointers, reference count access must be thread safe, **that** is the only guarantee that both offer. – David Rodríguez - dribeas Mar 21 '12 at 03:32
  • @Sqeaky: Yes, `boost::shared_ptr` does pull a few other headers. But you can go ahead and search for how to pull specific components from boost as standalone libraries and then use just the bits you care about. There are tools designed for this (I don't remember the name, I have never had to do that). – David Rodríguez - dribeas Mar 21 '12 at 03:33
  • @ildjarn Thank you for trying to help, rather than trying to argue with me. Even though boost is no longer an option, have an upvote. – Sqeaky Mar 21 '12 at 03:48
  • 1
    @Sqeaky Something isn’t automatically rude just because you disagree with it. I said that “I never buy” it because this excuse is advanced quite often, and in reality the Boost installer is pretty painless. That said, I agree that the documentation could make the dependencies of the individual modules clearer to facilitate separate installation. Finally, I agree with your comment about programmers not always having final say over such decisions – but surely you agree that this *isn’t* a valid technical argument, it’s a bad corporate decision process. – Konrad Rudolph Mar 21 '12 at 09:27
  • 3
    And I need to emphasise this point, if your company prevents you from using Boost in C++ projects, it’s broken – jump ship! This is simply not a viable environment for constructive work. Preventing use of libraries such as those in Boost is counter-productive and unreasonable. – Konrad Rudolph Mar 21 '12 at 09:29
  • @KonradRudolph Again your blanket statements are quite inflammatory and not helping me complete my goal. You seem to be under the assumption adding boost is *ALWAYS* a good idea. I really do agree with them in this case, this project has a ton of other libraries that provide most of the facilities that we need. I have used boost on other projects. I am not including a giant library for one pointer class. Instead of telling me to leave a company I very much enjoy in every way, you could have told me there are Two shared_ptr implementations when my description didn't match your expectiations. – Sqeaky Mar 21 '12 at 17:53
  • @David : The tool is called [bcp](http://www.boost.org/tools/bcp/). Sqeaky, yes, `boost::shared_ptr<>` is absolutely header-only, it's just not a single header. – ildjarn Mar 22 '12 at 18:16

4 Answers4

5

I'd take a look at the one in Loki. Loki is considerably smaller than boost, and the smart pointer implementation in Loki is highly configurable.

Ylisar
  • 4,293
  • 21
  • 27
3

boost shared_ptr supports single threading usage

you can #define the macro BOOST_SP_DISABLE_THREADS on a project-wide basis to switch to ordinary non-atomic reference count updates

citation from boost shared_ptr

ildjarn
  • 62,044
  • 9
  • 127
  • 211
Marius
  • 833
  • 5
  • 11
  • Thank you ildjarn and Marius, but this boost library lost out on 'administrative' reasons. It is too much effort changing the build system for too little payoff. – Sqeaky Mar 21 '12 at 03:30
  • @Sqeaky - I added the boost library to a legacy clearcase vob last year. No big deal... you only need the headers for shared_ptr anyway, so it won't affect anything outside of your project. You just need to put them somewhere accessible to the build environment. Shirley that's possible. – Dennis Mar 21 '12 at 11:45
  • @Dennis After I found a file called a shared_ptr.hpp I stopped looking (This one included 13+ other includes and at least 2 associated source files I mentioned above). Why is there a second? For reference I found them in the interprocess and smart_ptr folders. Even the implementation in the smart_ptr folder includes several other boost items that needlessly complicate the simple thing I need, I can't pull in a bunch of files. So if I do copy I will need to remove or relocate a bunch of stuff, I will look into it. – Sqeaky Mar 21 '12 at 17:51
  • 1
    @Sqeaky As an aside, I've also written a smart pointer implementation myself for a project stuck in MSVC++ 4.2, so that is an option. Not too difficult. See http://ootips.org/yonat/4dev/smart-pointers.html which is what I based mine on. Definitely a possibility if you want a small solution. Just the header and .cpp file required. – Dennis Mar 22 '12 at 13:55
  • @Dennis could you break your comment into an answer. Even though simplistic (Maybe I should say 'because of its simplicity') your shared pointer served as a decent place to start for customizing our own. We will probably flesh it out over time to have the same Interface as shared_ptr, but for now we just added use_count() and it seems to work for what we need. – Sqeaky Mar 26 '12 at 15:05
  • @Sqeaky I have done that now. Just to point out though, the pointer impl at the location is not mine. I just based my own versions off that as a start point. – Dennis Mar 26 '12 at 17:40
2

gcc has a class __shared_ptr which takes a lock-policy. shared_ptr derives off this.

One of the policies is _S_single, which is for single threaded code (ie: non locked/non atomic reference count)

In c++11 you can use template aliases which will allow you to use the non-standard __shared_ptr class which shared_ptr derives off

template<typename T>
using st_ptr = __shared_ptr<T, __gnu_cxx::_S_single>;

If you don't have a conformant compiler yet you can roll your own by just inheriting off __shared_ptr and exposing the interface (in fact this is how gcc currently does it because of the fact that template aliases were not available prior to 4.7)

Look in bits/shared_ptr.h to see how shared_ptr derives off __shared_ptr - it will be trivial to roll your own.

Steve Lorimer
  • 27,059
  • 17
  • 118
  • 213
  • That sounds like an awesome suggestion on GCC(have an upvote). However, this same code must compile on other compilers, at present Clang and MSVC, but we are moving additional compilers soon. In the more general sense, I did consider adjusting the lock policy through the 'proper' ways, and even if that worked, it was not obvious how to change it on other compilers. Even if we did change it on every compiler what would we do when we do want a thread safe shared_ptr. – Sqeaky Mar 26 '12 at 15:01
  • 1
    N.B. prior to GCC 4.9 (which is not released yet) your `st_ptr` alias would still use atomic ops in multi-threaded programs, see http://stackoverflow.com/a/15141844/981959 for more details. – Jonathan Wakely Nov 18 '13 at 13:57
1

It is quite possible to write/adapt your own smart pointer class for use in legacy projects that the newer libraries do not support. I have written my own for just such a reason and it works well with MSVC++ 4.2 and onwards.

See ootips.org/yonat/4dev/smart-pointers.html which is what I based mine on. Definitely a possibility if you want a small solution. Just the header and .cpp file required.

The key point to watch out for is the lack of the explicit keyword in older compilers. Another is that you may want to allow implicit conversion to the raw pointer to allow your APIs to remain less affected (we did this) and in that case you should also take care to prevent conversion to other types of pointers as well.

Dennis
  • 3,683
  • 1
  • 21
  • 43
  • Thanks for the suggestions. This definitely saved me some time vs rolling my own and no cpp file, just the single header, was required. I hope I don't run into to many older compilers, but I may not have control over that. With implicit conversion isn't there some risk of deleting the referenced item then leaving the caller's pointer invalid? Or do you have an article about how you designed that API? – Sqeaky Mar 27 '12 at 17:43
  • No, I don't have an article, as it is proprietary code. Yes there is a risk with implicit conversion that the raw pointer will be deleted, but you should be able to check the functions that you are allowing to implicitly convert the pointer. I only used this right at the beginning as this changed was being driven by a customer bug and I needed to get it out quickly. I could then update the APIs over a few weeks to use the reference object and then I could remove the implicit conversion. – Dennis Mar 28 '12 at 10:05