Is there a non-atomic equivalent of std::shared_ptr? And why isn't there one in ?

前端 未结 5 1681
闹比i
闹比i 2020-11-27 14:30

This is a bit of a two part question, all about the atomicity of std::shared_ptr:

1. As far as I can tell, std::shared_ptr

5条回答
  •  自闭症患者
    2020-11-27 14:52

    Howard's answered the question well already, and Nicol made some good points about the benefits of having a single standard shared pointer type, rather than lots of incompatible ones.

    While I completely agree with the committee's decision, I do think there is some benefit to using an unsynchronized shared_ptr-like type in special cases, so I've investigated the topic a few times.

    If I'm not using multiple threads, or if I am using multiple threads but am not sharing pointer ownership across threads, an atomic smart pointer is overkill.

    With GCC when your program doesn't use multiple threads shared_ptr doesn't use atomic ops for the refcount. This is done by updating the reference counts via wrapper functions that detect whether the program is multithreaded (on GNU/Linux this is done simply by detecting whether the program links to libpthread.so) and dispatch to atomic or non-atomic operations accordingly.

    I realised many years ago that because GCC's shared_ptr is implemented in terms of a __shared_ptr base class, it's possible to use the base class with the single-threaded locking policy even in multithreaded code, by explicitly using __shared_ptr. Unfortunately because that wasn't an intended use case it didn't quite work optimally before GCC 4.9, and some operations still used the wrapper functions and so dispatched to atomic operations even though you've explicitly requested the _S_single policy. See point (2) at http://gcc.gnu.org/ml/libstdc++/2007-10/msg00180.html for more details and a patch to GCC to allow the non-atomic implementation to be used even in multithreaded apps. I sat on that patch for years but I finally committed it for GCC 4.9, which allows you to use an alias template like this to define a shared pointer type that is not thread-safe, but is slightly faster:

    template
      using shared_ptr_unsynchronized = std::__shared_ptr;
    

    This type would not be interoperable with std::shared_ptr and would only be safe to use when it is guaranteed that the shared_ptr_unsynchronized objects would never be shared between threads without additional user-provided synchronization.

    This is of course completely non-portable, but sometimes that's OK. With the right preprocessor hacks your code would still work fine with other implementations if shared_ptr_unsynchronized is an alias for shared_ptr, it would just be a little faster with GCC.


    If you're using a GCC before 4.9 you could use that by adding the _Sp_counted_base<_S_single> explicit specializations to your own code (and ensuring noone ever instantiates __shared_ptr without including the specializations, to avoid ODR violations.) Adding such specializations of std types is technically undefined, but would work in practice, because in this case there's no difference between me adding the specializations to GCC or you adding them to your own code.

提交回复
热议问题