Question

I'm trying to replace a std::unordered_map with a tbb::concurrent_hash_map.

My original code:

typedef std::unique_ptr<V> V_ptr;

std::unordered_map<K, V_ptr> hm;
V_ptr v (new V);
K k;

hm.insert (std::make_pair (k, std::move (v)));

compiles fine with clang 3.3. Switching the unordered_map to a concurrent_hash_map:

typedef std::unique_ptr<V> V_ptr;

tbb::concurrent_hash_map<K, V_ptr> hm;
V_ptr v (new V);
K k;

hm.insert (std::make_pair (k, std::move (v)));

results in the error: ...stl_pair.h:105:21: error: call to deleted constructor of 'std::unique_ptr<...

Is this a bug in clang 3.3? I remember there being similar errors in gcc 4.5 when using std::unique_ptrs in many containers. (The above original code will not compile with gcc 4.5 for ex.) Or maybe I missed something about concurrent_hash_maps?

Was it helpful?

Solution

According to documentation tbb::concurrent_hash_map takes argument only via const& which triggers copy of unique_ptr:

bool insert( const value_type& value );

As workaround you may use std::shared_ptr or store unique_ptrs in stand-alone vector:

std::vector<std::unique_ptr<V>> ptrs;

and store raw pointers in concurrent_hash_map. Though, that may be not acceptable for your use cases (like frequent deletions).

Another possibility is to use std::auto_ptr or something similar. But that is dangerous - right copy should arrive into bucket, so you have to test it.

OTHER TIPS

Probably you can work around this limitation by using a more complex form of insertion into tbb::concurrent_hash_map. The following code snippet is not tested, but a priori I see no reason why it would not work:

typedef std::unique_ptr<V> V_ptr;

tbb::concurrent_hash_map<K, V_ptr> hm;
V_ptr v (new V);
K k;
{ // this scope controls lifetime of the accessor
    tbb::concurrent_hash_map::accessor a;
    hm.insert (a, k);          // insert or find the key
    a->second = std::move(v);  // assign the value
}

I agree that the answer to my question is that tbb does not support std::move yet. I'm going to stick with shared_ptr for now but the following work around does work:

struct V_ptr : public std::unique_ptr<V> {

    typedef std::unique_ptr<V> uvptr;
    using uvptr::uvptr;
    V_ptr () : std::unique_ptr<V> () {};

    V_ptr (const V_ptr& rhs) {
        this->swap (const_cast<V_ptr&> (rhs));
    }
};

Though I'm hesitant to recommend it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top