C ++ 11在BST中魔术地删除了构造函数 [英] C++11 Magically Deleted Constructor in 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_ptr
s.
特别感谢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屋!