在实现BS树的过程中,我注意到自从我开始使用C ++ 11智能指针以来我不太确定的事情,这让我想知道为什么会这样。如果我使用 init-brace pairs {} 而不是括号,下面的代码工作正常;我的个人规则是为每个成员(直接或通过ctor)初始化值,因为 Node :: right 和 Node :: left 都是因此,智能指针是 nullptr 。 问题1 :为什么括号失败并且init-brace对成功?在这种情况下,两者之间是否存在语义差异?
在 BST 中,在采用std :: initializer_list的ctor中,据我所知,std :: initializer_list元素只能复制,根据this。因此,如果我没有错,根据Scott Meyer在最近的GN13中,对const对象执行移动只会触发对象的复制。
Quesion 2 为什么编译器在调用 BST :: insert(T&&)时无法复制对象?
#include <memory>
template<typename T>
struct Node
{
//~ std::unique_ptr<Node<T>> left ( nullptr ), right ( nullptr );
std::unique_ptr<Node<T>> left { nullptr }, right { nullptr };
Node<T> *parent = nullptr;
T value { };
Node<T> () = default;
Node<T> ( T && val, Node<T> * _left = nullptr, Node<T> *_right = nullptr,
Node<T> *_parent = nullptr ): left( _left ), right ( _right ), parent( _parent ),
value ( std::move( val ) )
{
}
};
template<typename T>
struct BinarySearchTree
{
std::unique_ptr<Node<T>> root;
BinarySearchTree(): root { nullptr } { }
BinarySearchTree( std::initializer_list<T> && lst ): BinarySearchTree { }{
//If the below code were changed to
//~ for( auto && i: lst ){ it would be an error
for( typename std::remove_reference<typename std::remove_const<T>::type>::type i: lst ){
this->insert( std::move( i ) );
}
}
void insert( T && v ) { }
};
int main(){
BinarySearchTree<int> a { 11, 24 };
return 0;
}
答案 0 :(得分:3)
为什么括号失败并且init-brace对成功?
因为括号用于函数声明。您不能使用它们来初始化类范围内的变量。即使int i(1);
也无法工作。
为什么编译器在调用BST :: insert(T&amp;&amp;)时无法复制对象?
你在比较中不公平。在auto
版本中,您明确要求引用类型。在非auto
版本中,您明确要求使用非引用类型。删除&&
会使auto
版本也正常工作。
您的insert
方法需要T &&
。这是一个非const
限定的引用,因此无法绑定到任何const
对象。
auto &&
推断为const int &&
,因为您无法更改initializer_list<int>
的内容:其begin()
和end()
方法返回const int *
。添加std::move
无法正常工作,您无法绕过const
。
auto
会推断为int
,并会有效:您将获得一个新的非const
int
局部变量i
,其中包含初始化列表中的值的副本。您可以对该局部变量形成非const
引用。