C ++使用已删除的函数错误

时间:2015-08-03 16:09:47

标签: c++ c++11 smart-pointers

我大量使用已删除的功能错误。我刚刚将weighted_pointer的指针更改为unique_ptr。但我无法理解为什么我会收到错误,任何提示?

likeatree是一个DAG结构,可以根据掩码值指向另一个结构或stdDeque的元素。

weight的{​​{1}}有weighted_pointer个关键字,因为它不会改变集合中的位置。

mutable

编辑:使用单个案例更改了代码 编辑:已解决。使用make_unique时缺少取消引用。

3 个答案:

答案 0 :(得分:6)

你的结构在这里:

struct weighted_pointer{
    mutable int weight;
    unique_ptr<likeatree> ptr;
};

包含std::unique_ptr。无法复制std::unique_ptr,因此您的整个weighted_pointer也无法复制。

您的代码中有三个地方尝试复制它,这会导致您看到的错误:

bool operator()(const weighted_pointer lhs, const weighted_pointer rhs) {

必须:

bool operator()(weighted_pointer const& lhs, weighted_pointer const& rhs) {
stdSet.insert(tmp);

理论上可以通过以下方法解决:

stdSet.insert(std::move(tmp));

然而,你不能再使用tmp了,不仅在同一个循环中,而且在下面的循环中。所以你必须完全找到一个不同的解决方案。也许使用emplace。或者完全重构您的代码。

auto it = find_if(stdSet.begin(),stdSet.end(),[&](weighted_pointer temp){ return temp.ptr.get() == treeVector[i]; });

必须:

auto it = find_if(stdSet.begin(),stdSet.end(),[&](weighted_pointer const& temp){ return temp.ptr.get() == treeVector[i]; });

对于VC ++ 2013,std::move修复是不够的。您必须在结构中添加一个显式移动构造函数:

struct weighted_pointer{
    mutable int weight;
    unique_ptr<likeatree> ptr;

    weighted_pointer() = default;
    weighted_pointer(weighted_pointer&& src) :
        weight(std::move(src.weight)),
        ptr(std::move(src.ptr))
    {
    }
};

VC ++ 2015修复了这个问题。更多信息:Default Move Constructor in Visual Studio 2013 (Update 3)

答案 1 :(得分:3)

您的weighted_pointer是不可复制的,因为它包含一个不可复制的成员(unique_ptr),因此您必须通过const引用将其传递给比较器函数。

bool operator()(const weighted_pointer& lhs, const weighted_pointer& rhs)

这是因为如果你按值传递它(因为它是当前编写的),它将尝试创建一个函数本地副本。

您也无法执行此操作,因为您正在尝试复制tmp,正如我刚才所说,struct是不可复制的。

for(unsigned int i = 0; i < stdDeque.size(); i++){
    tmp.ptr.reset(new likeatree{0,&stdDeque[i],nullptr});
    stdSet.insert(tmp);
}

您可以使用emplace来构建weighted_pointer,而不是

for(unsigned int i = 0; i < stdDeque.size(); i++){
    stdSet.emplace(1, std::make_unique<likeatree>(0,&stdDeque[i],nullptr));
}

答案 2 :(得分:0)

当我编译上面的代码时,编译器说:

In file included from /usr/include/c++/4.8/algorithm:62:0,
                 from 31791982.cpp:7:
/usr/include/c++/4.8/bits/stl_algo.h: In instantiation of ‘_InputIterator std::__find_if(_InputIterator, _InputIterator, _Predicate, std::input_iterator_tag) [with _InputIterator = std::_Rb_tree_const_iterator<weighted_pointer>; _Predicate = main()::__lambda0]’:
/usr/include/c++/4.8/bits/stl_algo.h:4465:41:   required from ‘_IIter std::find_if(_IIter, _IIter, _Predicate) [with _IIter = std::_Rb_tree_const_iterator<weighted_pointer>; _Predicate = main()::__lambda0]’
31791982.cpp:55:124:   required from here

请看第55行 - 发生了什么:

    auto it = find_if(stdSet.begin(),stdSet.end(),[&](weighted_pointer temp){ return temp.ptr.get() == treeVector[i]; });

我们正在尝试将数组中的weighted_pointer复制到lambda&#39; temp中。但实际上,我们对const引用感到满意,所以用const weighted_pointer&替换并再次编译:

/usr/include/c++/4.8/bits/stl_tree.h: In instantiation of ‘std::pair<std::_Rb_tree_node_base*, std::_Rb_tree_node_base*> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_get_insert_unique_pos(const key_type&) [with _Key = weighted_pointer; _Val = weighted_pointer; _KeyOfValue = std::_Identity<weighted_pointer>; _Compare = ptrcomp; _Alloc = std::allocator<weighted_pointer>; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::key_type = weighted_pointer]’:
/usr/include/c++/4.8/bits/stl_tree.h:1377:47:   required from ‘std::pair<std::_Rb_tree_iterator<_Val>, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(_Arg&&) [with _Arg = const weighted_pointer&; _Key = weighted_pointer; _Val = weighted_pointer; _KeyOfValue = std::_Identity<weighted_pointer>; _Compare = ptrcomp; _Alloc = std::allocator<weighted_pointer>]’
/usr/include/c++/4.8/bits/stl_set.h:463:29:   required from ‘std::pair<typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename _Alloc::rebind<_Key>::other>::const_iterator, bool> std::set<_Key, _Compare, _Alloc>::insert(const value_type&) [with _Key = weighted_pointer; _Compare = ptrcomp; _Alloc = std::allocator<weighted_pointer>; typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename _Alloc::rebind<_Key>::other>::const_iterator = std::_Rb_tree_const_iterator<weighted_pointer>; std::set<_Key, _Compare, _Alloc>::value_type = weighted_pointer]’
31791982.cpp:49:26:   required from here

第49行是:

    stdSet.insert(tmp);

我们无法将tmp复制到集合中。如果我们不能重复使用tmp,我们可以改为移动它:

for(unsigned int i = 0; i < stdDeque.size(); i++){
    weighted_pointer tmp;
    tmp.weight = 1;
    tmp.ptr.reset(new likeatree{0,&stdDeque[i],nullptr});
    stdSet.insert(std::move(tmp));
}

然后,我们为ptrcomp::operator()提供了一个简单的修复方法,它需要通过const引用来接受它的参数。