1

C ++ 11の新しいメモリ<memory>ヘッダーについての私の理解は少し週ですが、shared_ptrはrefcounted ptrであるため、コピーするのに非常にコストがかかります(特に、ARMアーチなど)。そして、unique_ptrは、new/deleteの非常に軽いラッパーです。また、可動式なので、作成した範囲に制限されることはありません。
だから私の質問は:
shared_ptrがunique_ptrよりも優先されるシングルスレッドコードの使用法はありますか?

シングルスレッドコードを将来のマルチスレッドに対応できるようにするなどの回答には興味がありません。コードがsinglthreadedであると仮定します。

4

2 に答える 2

4

Your dwelling on threading here is kind of a red herring; there's a clear contrast between the two, and it has little to nothing to do with threads. If you're using these classes in a single-threaded environment, you may be able to turn off the atomic operations support; for example, with Boost, define the macro BOOST_SP_DISABLE_THREADS.

You use shared_ptr<> when you're not quite sure what the lifetime of an object will be, and want "the last guy in the room to shut off the lights" -- i.e., you don't want the object to be deleted until no client is using it any longer. You use unique_ptr<> when you know exactly who is going to delete the object -- i.e., when the lifetime of the pointed-to object is precisely delimitated by a scope.

It is true that copying a shared_ptr<> is not free, but it's far from "really, really expensive." You pay a little bit for the reference counting overhead, but that's the whole point of using it: you need to keep track of the clients of the object; there's a little cost involved, but you get the benefit of not leaking the object.

于 2012-07-26T11:01:18.917 に答える
2

This is a very good question.

In a multi-threaded build one basically always pays for atomic reference counter increments/decrements made by shared_ptr<>, even if objects never get shared between threads.

The other drawback is that the size of shared_ptr<> is double the size of a plain pointer.

For these two reasons shared_ptr<> has never been a good choice for performance critical applications.

Multi-threaded applications have a few types of objects that are shared between thread and the majority that are not. Using atomic reference counter increment/decrement is only required for the thread-shared objects and it is silly to pay atomic operation costs for the majority of other objects. Hence it makes good sense to have different (base) types for thread-shared and thread-non-shared objects and manage them using boost::intrusive_ptr<>. Thread-shared objects have an atomic reference counter while thread-non-shared object get a plain integer counter. E.g.:

#include <atomic>
#include <boost/intrusive_ptr.hpp>

template<class Derived, class Counter>
class RefCounter
{
    Counter ref_count_;

    friend void intrusive_ptr_add_ref(RefCounter* p) {
        ++p->ref_count_;
    }

    friend void intrusive_ptr_release(RefCounter* p) {
        if(!--p->ref_count_)
            delete static_cast<Derived*>(p);
    }

protected:
    RefCounter() : ref_count_() {}
};

class NonThreadShared
    : public RefCounter<NonThreadShared, unsigned>
{};

class ThreadShared
    : public RefCounter<ThreadShared, std::atomic<unsigned> >
{};

int main() {
    boost::intrusive_ptr<NonThreadShared> p(new NonThreadShared);
    boost::intrusive_ptr<ThreadShared> q(new ThreadShared);
}
于 2012-07-26T12:19:57.083 に答える