这种将数据从标准容器移动到共享指针的方法是否正确?

时间:2014-02-06 03:36:38

标签: c++ c++11

这是我的问题:有时我在函数中定义了一个std :: string。由于异步操作,我需要扩展字符串的范围。当然,我可以将它复制到这样的共享指针:

{
std::string hi{"hi"};
auto shared_hi = std::make_shared<std::string>(hi);
//insert shared_hi in async queue
}

这个问题是有时我的字符串非常非常大,有时它们是向量,有时它们是std :: arrays。所以我不仅要避免副本,而且我还希望有一个可以“偷”&#34;容器中的数据无需复制。我在下面发布了一个聪明的解决方案,但我想知道是否有更好的解决方案。如果没有,我想知道我在下面做的事情是否定义了行为:

template<class T>
class WrappedDeleter {
public:
  WrappedDeleter(T  &&other): o_(std::move(other)) {
  }
private:
  T o_;
};

//This function creates a deleter where the scope
template<class P, class T>
std::function<void(P *)> make_delete(T  &&encapsulate) {
  WrappedDeleter<T> *d = new WrappedDeleter<T>(std::move(encapsulate));
  return [d](P * ptr) {
    std::cout << "deleting now\n";
    delete d;
  };
}

template<class P, class C>
std::shared_ptr<P> steal_data(C  &&data) {
  P *ptr = data.data();
  //can't use make_shared - custom deleter
  return std::shared_ptr<P>(ptr, make_delete<P, C>(std::move(data)));
}

像这样使用:

int main() {
    {
        std::shared_ptr<int> p_a;
        std::shared_ptr<int> p_b;
        std::shared_ptr<const char> p_c;

        {
            std::array<int,3> a= {{1,2,3}};
            std::vector<int> b= {1,2,3};
            std::string c= {"hello world"};
            p_a = steal_data<int,std::array<int,3> >(std::move(a));
            p_b = steal_data<int, std::vector<int> >(std::move(b));
            p_c = steal_data<const char, std::string>(std::move(c));
            std::cout << "inside" << *p_a << " " << *p_b << " " << p_c.get() << std::endl;
        }
        std::cout << "outside" << *p_a << " " << *p_b << " " << p_c.get() << std::endl;


        std::cout << "end of scope\n";
    }
    return 0;
}

1 个答案:

答案 0 :(得分:2)

正如Praetorian所说,将数据移入shared_ptr的唯一合理方法是使用make_shared<T>(move(obj))。如果您希望shared_ptr指向基础连续数据块而不是容器本身,则可以使用别名构造函数template<class Y> shared_ptr(const shared_ptr<Y>& r, T *ptr);

std::vector<int> v{1, 2, 3};
auto cptr = std::make_shared<std::vector<int>>(std::move(v));
std::shared_ptr<int> ptr{cptr, cptr->data()};

作为一项功能:

template<typename Container>
std::shared_ptr<Container::value_type> steal_data(Container &&cont) {
    auto cptr = std::make_shared<Container>(std::move(cont));
    return {cptr, cptr->data()};
}