How to deal with noncopyable objects when inserting to containers in C++

后端 未结 2 788
旧时难觅i
旧时难觅i 2021-02-07 18:31

I\'m looking for the best-practice of dealing with non-copyable objects.

I have a mutex class, that obviously should not be copyable. I added a private copy constructor

相关标签:
2条回答
  • 2021-02-07 18:58

    If they are non-copyable, the container has to store (smart) pointers to those objects, or reference wrappers, etc, although with C++0x, noncopyable objects can still be movable (like boost threads), so that they can be stored in containers as-is.

    to give examples: reference wrapper (aka boost::ref, a pointer under the hood)

    #include <vector>
    #include <tr1/functional>
    struct Noncopy {
    private:
            Noncopy(const Noncopy&) {}
    public:
            Noncopy() {}
    };
    int main()
    {
            std::vector<std::tr1::reference_wrapper<Noncopy> > v;
            Noncopy m;
            v.push_back(std::tr1::reference_wrapper<Noncopy>(m));
    }
    

    C++0x, tested with gcc:

    #include <vector>
    struct Movable {
    private:
            Movable(const Movable&) = delete;
    public:
            Movable() {}
            Movable(Movable&&) {}
    };
    int main()
    {
            std::vector<Movable> v;
            Movable m;
            v.emplace_back(std::move(m));
    }
    

    EDIT: Nevermind, C++0x FCD says, under 30.4.1/3,

    A Mutex type shall not be copyable nor movable.

    So you're better off with pointers to them. Smart or otherwise wrapped as necessary.

    0 讨论(0)
  • 2021-02-07 19:10

    Three solutions here:

    1. Use Pointers - The quick fix is to make it a container of pointers - e.g. a shared_ptr.

    That would be the "good" solution if your objects are truly noncopyable, and using other containers is not possible.

    2. Other containers - Alternatively, you could use non-copying containers (that use in-place-construction), however they aren't very common and largely incompatible with STL. (I've tried for a while, but it's simply no good)

    That would be the "god" solution if your objects are truly noncopyable, and using pointers is not possible.

    [edit] With C++13, std::vector allows inplace construction (emplace_back), and can be used for noncopyable objects that do implement move semantics. [/edit]

    3. Fix your copyability - If your class is copyable as such, and the mutex is not, you "simply" need to fix the copy constructor and assignment operator.

    Writing them is a pain, since you usually have to copy & assign all members except the mutex, but that can often be simplified by:

    template <typename TNonCopyable>
    struct NeverCopy : public T 
    {
        NeverCopy() {}
        NeverCopy(T const & rhs) {}
    
        NeverCopy<T> & operator=(T const & rhs) { return *this; }
    }
    

    And changing you mutex member to

    NeverCopy<Mutex> m_mutex;
    

    Unfortunately, using that template you lose special constructors of Mutex.

    [edit] Warning: "Fixing" the Copy CTor/asignment often requires you to lock the right hand side on copy construct, and lock both sides on assignment. Unfortunately, there is no way to override the copy ctor/assignment and call the default implementation, so the NeverCopy trick might not work for you without external locking. (There are some other workarounds with their own limitations.)

    0 讨论(0)
提交回复
热议问题