C ++ 11在BST中魔术地删除了构造函数 [英] C++11 Magically Deleted Constructor in BST

查看:150
本文介绍了C ++ 11在BST中魔术地删除了构造函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

已解决!请参阅下面

因此,我试图通过一些简单的数据结构学习C ++ 11,并与他们一起玩。我使用原始指针和 new delete 对以下BST示例执行了类似它工作正常。然后我想以更安全的方式做。

So, I'm trying to learn C++11 by doing some simple data structures and playing around with them. I did something similar to the following BST example using raw pointers and new and delete and it worked fine. Then I wanted to do it in a way that was more leak-safe.

// tree.cpp
// 
// 

#include <iostream>
#include <memory>

/* DECLARATIONS */
template <typename T>
struct Tree {
  // members
  T data;
  std::unique_ptr<Tree<T> > left;
  std::unique_ptr<Tree<T> > right;
  // methods
  Tree (T arg);
  ~Tree () = default;
  void insert (Tree<T> child);
  void insert (T arg);
  void print (void);
};

template <typename T>
Tree<T>::Tree (T arg) {
  data = arg;
  left = nullptr;
  right = nullptr;
}

template <typename T>
void Tree<T>::insert (Tree<T> child) {
  if (child.data < data) {
    if (left) {
      left->insert(child);
    } else {
      left = &child;
    }
  } else {
    if (right) {
      right->insert(child);
    } else {
      right = &child;
    }
  }
}

template <typename T>
void Tree<T>::insert (T arg) {
  Tree<T> child (arg);
  this->insert(child);
}

template <typename T>
void Tree<T>::print (void) {
  if (left) {
    left->print();
  }
  std::cout << data;
  if (right) {
    right->print();
  }
}

int main (void) {
  Tree<int> root (0);
  root.insert(3);
  root.insert(-3);
  root.insert(-2);
  root.insert(2);
  root.insert(11);
  root.print();
  return 0;
}

然而,我不会忽略我从clang ++得到的错误。

I don't undersatnd the error I'm getting from clang++, however.

$ clang ++ -std = c ++ 11 tree.cpp

tree_new.cpp:50:16: error: call to deleted constructor of 'Tree<int>'
  this->insert(child);
               ^~~~~
tree_new.cpp:66:8: note: in instantiation of member function 'Tree<int>::insert'         requested here
   root.insert(3);
   ^
tree_new.cpp:10:8: note: function has been explicitly marked deleted here
struct Tree {
       ^
tree_new.cpp:18:24: note: passing argument to parameter 'child' here
  void insert (Tree<T> child);
                       ^
tree_new.cpp:34:20: error: call to deleted constructor of 'Tree<int>'
  left->insert(child);
               ^~~~~
tree_new.cpp:50:9: note: in instantiation of member function 'Tree<int>::insert'requested here
  this->insert(child);
        ^
tree_new.cpp:66:8: note: in instantiation of member function 'Tree<int>::insert' requested here
  root.insert(3);
       ^
tree_new.cpp:10:8: note: function has been explicitly marked deleted here
struct Tree {
       ^
tree_new.cpp:18:24: note: passing argument to parameter 'child' here
  void insert (Tree<T> child);
                       ^
2 errors generated.

为什么说我明确删除了构造函数,当我声明 struct ?我甚至明确定义了一个构造函数!此外,任何关于范围界定/所有权失败的意见将不胜感激。

Why does it say I explicitly deleted the constructor when I declared the struct? I even defined a constructor explicitly! Also, any comments on scoping/ownership failure would be appreciated. I'm pretty sure this won't work the way I did it anyways.

解决方案

MSDN 的以下链接阐明了可以使用 unique_ptr

The following link from MSDN clarified how one can use unique_ptrs.

特别感谢BatchyX对问题的初步解释(使用 unique_ptr 作为一个成员隐式(虽然编译器说显式...)删除该类的复制构造函数,并注意到确实Tree仍然可移动。

Special thanks to BatchyX for his initial explanation of the problem (using a unique_ptr as a member implicitly (though the compiler says "explicitly"...) deletes the copy constructor for the class), and for noting that indeed Tree is still movable.

在MSDN文章中提到的是, std :: move()返回其参数的右值。

Something mentioned in that MSDN article is that std::move() returns an rvalue of its argument.

这里是适当修改的代码(不包括明显修改的声明)。注意,可能还有一些优化可能仍然使用std :: forward,但这至少似乎编译和运行正确。

Here is the suitably modified code (excluding the obviously modified declarations). Note that there might be some optimizations possible still by using std::forward, but this at least seems to compile and run correctly.

template <typename T>
void Tree<T>::insert (std::unique_ptr<Tree<T> >&& pchild) {
  if (pchild->data < data) {
    if (left) {
      // recurse, but must match on the rvalue signature
      left->insert(std::move(pchild));
    } else {
      // invokes the move constructor for left instead of its copy constructor
      left = std::move(pchild);
    }
  } else {
    if (right) {
      right->insert(std::move(pchild));
    } else {
      right = std::move(pchild);
    }
  }
}

template <typename T>
void Tree<T>::insert (T arg) {
  // what is inside the insert(...) is an rvalue.
  this->insert(std::unique_ptr<Tree<T> >(new Tree<T> (arg)));
}


推荐答案

std :: unique_ptr 不可复制,任何包含 unique_ptr 的类也不可复制,意味着 struct Tree 不可复制。参数:

std::unique_ptr is not copyable, and any class that contains a unique_ptr is also not copyable, meaning struct Tree is not copyable. The argument to:

void Tree<T>::insert (Tree<T> child) {

按值取其参数。和:

template <typename T>
void Tree<T>::insert (T arg) {
  Tree<T> child (arg);
  this->insert(child);
}

需要复制构造函数。要更正此问题,请使 struct Tree 可移动。

requires the copy constructor. To correct this, make struct Tree moveable.

code> Tree 是不是可移动(与 BatchyX <由于存在:

Note Tree is not moveable (in contrast to BatchyX's comment) due to the presence of:

~Tree () = default;

这是用户声明的析构函数,复制和移动类对象(第9点)的c ++ 11标准(草案n3337):

which is a user-declared destructor and from section 12.8 Copying and moving class objects (point 9) of the c++11 standard (draft n3337):


的类X没有显式声明一个移动构造函数,
一个将隐式声明为默认值,如果且仅当

If the definition of a class X does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if


  • X没有用户声明的复制构造函数

  • X没有用户声明的复制赋值运算符,

  • X没有用户-declared move assignment operator,

  • X没有用户声明的析构函数

  • 不会隐式定义为已删除。

  • X does not have a user-declared copy constructor,
  • X does not have a user-declared copy assignment operator,
  • X does not have a user-declared move assignment operator,
  • X does not have a user-declared destructor, and
  • the move constructor would not be implicitly defined as deleted.

并要求问题确定)。要使其可移动,请执行以下操作:

(I was uncertain about the implicit generation of the move members and asked this question to be certain). To make it moveable either:


  • 删除用户声明的析构函数,或

  • 构造函数和移动赋值运算符

这篇关于C ++ 11在BST中魔术地删除了构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆