【问题标题】:C++ Use of deleted function errorC++ 使用已删除函数错误
【发布时间】:2015-10-25 20:05:16
【问题描述】:

我经常使用已删除的函数错误。我只是将weighted_pointer 的指针更改为unique_ptr。但我不明白为什么会出现错误,有什么提示吗?

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

weighted_pointerweight 具有 mutable 关键字,因为不会改变集合中的位置。

#include <deque>
#include <set>
#include <vector>
#include <iostream>
#include <algorithm>
#include <memory>
#include <chrono>

using namespace std;

struct likeatree{
    unsigned int mask : 3;
    void * a;
    void * b;
};

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

struct ptrcomp{
    bool operator()(const weighted_pointer & lhs, const weighted_pointer & rhs) {
        if(lhs.ptr->mask < rhs.ptr->mask)
            return true;
        if(lhs.ptr->mask > rhs.ptr->mask)
            return false;
        if(lhs.ptr -> a < rhs.ptr->a)
            return true;
        if(lhs.ptr->a > rhs.ptr->a)
            return false;
        return lhs.ptr->b < rhs.ptr->b;
    }
};

vector<likeatree *> treeVector;
deque<bool> stdDeque(3);
vector<vector<bool>> boolMatrix{{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0}};
set<weighted_pointer,ptrcomp> stdSet;

int main(){
    srand(time(NULL));
    likeatree * first_pointer = new likeatree{0,&input[0],nullptr};
    likeatree * second_pointer = first_pointer;
    unique_ptr<likeatree> tmp(first_pointer);
    weighted_pointer wp;
    wp.weight = 1;
    wp.pointer = move(tmp);
    stdSet.insert(move(wp));
    // I'd like to do it inline(or more but with variables that end of scope here), but this don't work. (And i don't keep a copy of the pointer)
    // stdSet.insert(move(weighted_pointer{1,move(make_unique<likeatree>(*new likeatree{0,&input[0],nullptr}))}));
    return 0;   
}

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

【问题讨论】:

  • 如果您包含实际的编译器错误,您将获得更好的答案(并且可能对错误的解释有所了解)。您正在使用的编译器选项也很有用。我用g++ -std=c++11 -c /tmp/31791982.cpp 编译它没有错误(尽管我无法成功链接,因为缺少main())。
  • @TobySpeight -std=c++11 -Wall。主要在最后。
  • 顺便说一句,你可以写bool ptrcomp::operator()(const weighted_pointer&amp; lhs, const weighted_pointer&amp; rhs) { return std::tie(lhs.ptr-&gt;mask, lhs.ptr-&gt;a, lhs.ptr-&gt;b) &lt; std::tie(rhs.ptr-&gt;mask, rhs.ptr-&gt;a, rhs.ptr-&gt;b); }
  • @TobySpeight: 没有看到位域:-(,我们仍然可以在这里使用make_tuple 而不是std::tie

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


【解决方案1】:

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

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 的 temp 中。但实际上,我们会对 const ref 感​​到满意,所以替换为 const weighted_pointer&amp; 并再次编译:

/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 引用接受其参数的问题。

【讨论】:

    【解决方案2】:

    你的结构在这里:

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

    包含std::unique_ptrstd::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)

    【讨论】:

    • 现在我意识到了。我忘记了没有参考它复制它。在我看来,我指的是它,但在编写代码时我忘了这样做:P 我回家后会改变一切,但这可能是主要问题。
    【解决方案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));
    }
    

    【讨论】:

    • 仍然得到 [错误] 使用已删除的函数 'weighted_pointer::weighted_pointer(const weighted_pointer&)'
    • @UmurilLyerood 我编辑了我的帖子,你有另一个地方要复制这个课程。您的错误消息将指示违规行,如果您看到更多这样的消息,请确保该类没有被复制到代码中的任何位置。
    • [错误] 'make_unique' 未在此范围内声明。 c++11 不允许,但是 np.我把它改成了c++14。 tmp 变量也在下面使用。我无法就地完成。
    • @UmuriLyerood:您要么必须移动 tmp 并重组代码,以便不再使用已移动的对象,要么使用 emplace。或者不使用std::unique_ptr
    猜你喜欢
    • 1970-01-01
    • 2016-07-27
    • 2021-01-30
    • 2021-08-25
    • 1970-01-01
    • 2022-01-07
    • 2014-04-16
    • 1970-01-01
    • 2021-12-28
    相关资源
    最近更新 更多