C++ 类: one 'reset' 如何在移动构造函数中创建模板字段?
C++ classes: How does one 'reset' a template field in the move constructor?
我是初学者,我希望我不会因为不懂术语而重复发帖,但我搜索了 Stack Overflow 和 Google 仍然没有找到我的答案问题,或者至少是我能理解的答案。
我正在为单链表作业编写节点 class。 class 有两个字段:elem 和 next。 Elem 是模板化的,next 是一个 Node 指针。
我决定编写一个自定义构造函数(以及所有其他构造函数),这样我就可以确定 next 被每个新节点初始化为 nullptr,所以我不会 运行 陷入困境指针问题。 class header:
template <typename E>
class Node {
public:
//Constructors
Node();
Node( const Node<E> &other); //copy
Node<E>& operator=( Node<E> other ); //copy asn
Node( Node&& other ); //move
Node<E>& operator=( Node<E>&& other ); //move asn
~Node();
// {...Getters and setters and the like...}
private:
E elem{}; //datatype independent element
Node<E>* next; //pointer to next list item
};
我的问题是编写移动构造函数。据我了解,移动构造函数的基本轮廓如下:
myClass( myClass&& otherMyClassObj ) {
// Step 1: Steal object's resources
myClassField = otherMyClassObj.myClassField;
myClassOtherField = otherMyClassObj.myClassOtherField;
/* ...etc... */
// Step 2: Set other object to a valid but default state so it will be deleted
otherMyClassObj.myClassField = <whatever is default for type>;
otherMyClassObj.myClassOtherField = <whatever is default for type>;
/*...etc...*/
}
当我尝试应用此大纲在我的 class 中编写移动构造函数时,我 运行 遇到了一个问题:elem 的默认状态是什么,我不知道它的类型知道是因为它是在运行时间确定的吗?我的移动构造函数代码:
template <typename E>
Node::Node( Node&& other ) {
next = other.next;
elem = other.elem;
other.next = nullptr;
other.elem = /* ???? */
}
我能想到的唯一解决方案是手动调用 other 上的析构函数,但这似乎草率且错误。我不能使用 nullptr,因为 elem 不一定是指针,但我不能使用 0,因为它 可能 是一个。我考虑过的另一种可能性是以某种方式直接在 elem 上调用 std::move(),但我不确定该怎么做,而且在移动构造函数中调用移动构造函数似乎本质上是错误的。
我真的很感激在这个问题上的一些帮助。请不要提出非标准的图书馆建议——我很乐意使用它们,但我的教授对我们使用哪些图书馆非常严格。
移动每个成员即可。
template <typename E>
Node::Node<E>( Node<E> && other ) : next(std::move(other.next)), elem(std::move(other.elem))
{
}
请注意,我不确定上面的确切模板语法。
遵守五规则是好事,但如果你不想在某些构造函数、赋值运算符或析构函数中做任何特殊的事情,那么考虑将它们设为 = default
。这让您的事情变得更轻松、更安全。
我们对 E
的唯一了解是 default c-tor
,否则代码无法编译。
一般来说,c-tor 的移动看起来像 Werner Henze 建议的那样。不过我建议你也重置指针。
template <typename E>
Node::Node<E>( Node<E> && other ) :
next(std::move(other.next)), // line 1
elem(std::move(other.elem)){ // line 2
// change to NULL for pre C++11
other.next = nullptr; // line 3
}
这是怎么回事?
解释如下:
- 第 1 行 - 我们移动指针。指针不能真正移动。它被复制了。不过保持
std::move
是个好习惯,只为"show the intention"你感动。
- 第 2 行 - 我们移动数据。这里有可能性:
- 如果
E
是movable
class,这步class。
- 如果
E
不是move-able
class,而是copy-able
(最简单的例子是int
),复制
- 如果
E
不是 move-able
class,也不是 copy-able
。这不会编译。
第2行执行后,E
处于valid
状态,但不能使用,因为里面可能有不同的数据。您可以销毁它或分配它。
- 第 2 行 - 这里我们重置指针,因为
d-tor
可能决定用它做一些事情。
备选
最后我会给你 move c-tor
的替代代码 - 使用 swap
.
它可能会更慢,但出于教育目的是可以的。
template <typename E>
Node::Node<E>( Node<E> && other ){
// "this" class is created now.
using std::swap;
swap(next, other.next);
swap(elem, elem);
}
最后的注释:
这里不需要{}
:
private:
E elem{}; //datatype independent element
这就够了:
private:
E elem; //datatype independent element
我是初学者,我希望我不会因为不懂术语而重复发帖,但我搜索了 Stack Overflow 和 Google 仍然没有找到我的答案问题,或者至少是我能理解的答案。
我正在为单链表作业编写节点 class。 class 有两个字段:elem 和 next。 Elem 是模板化的,next 是一个 Node 指针。
我决定编写一个自定义构造函数(以及所有其他构造函数),这样我就可以确定 next 被每个新节点初始化为 nullptr,所以我不会 运行 陷入困境指针问题。 class header:
template <typename E>
class Node {
public:
//Constructors
Node();
Node( const Node<E> &other); //copy
Node<E>& operator=( Node<E> other ); //copy asn
Node( Node&& other ); //move
Node<E>& operator=( Node<E>&& other ); //move asn
~Node();
// {...Getters and setters and the like...}
private:
E elem{}; //datatype independent element
Node<E>* next; //pointer to next list item
};
我的问题是编写移动构造函数。据我了解,移动构造函数的基本轮廓如下:
myClass( myClass&& otherMyClassObj ) {
// Step 1: Steal object's resources
myClassField = otherMyClassObj.myClassField;
myClassOtherField = otherMyClassObj.myClassOtherField;
/* ...etc... */
// Step 2: Set other object to a valid but default state so it will be deleted
otherMyClassObj.myClassField = <whatever is default for type>;
otherMyClassObj.myClassOtherField = <whatever is default for type>;
/*...etc...*/
}
当我尝试应用此大纲在我的 class 中编写移动构造函数时,我 运行 遇到了一个问题:elem 的默认状态是什么,我不知道它的类型知道是因为它是在运行时间确定的吗?我的移动构造函数代码:
template <typename E>
Node::Node( Node&& other ) {
next = other.next;
elem = other.elem;
other.next = nullptr;
other.elem = /* ???? */
}
我能想到的唯一解决方案是手动调用 other 上的析构函数,但这似乎草率且错误。我不能使用 nullptr,因为 elem 不一定是指针,但我不能使用 0,因为它 可能 是一个。我考虑过的另一种可能性是以某种方式直接在 elem 上调用 std::move(),但我不确定该怎么做,而且在移动构造函数中调用移动构造函数似乎本质上是错误的。
我真的很感激在这个问题上的一些帮助。请不要提出非标准的图书馆建议——我很乐意使用它们,但我的教授对我们使用哪些图书馆非常严格。
移动每个成员即可。
template <typename E>
Node::Node<E>( Node<E> && other ) : next(std::move(other.next)), elem(std::move(other.elem))
{
}
请注意,我不确定上面的确切模板语法。
遵守五规则是好事,但如果你不想在某些构造函数、赋值运算符或析构函数中做任何特殊的事情,那么考虑将它们设为 = default
。这让您的事情变得更轻松、更安全。
我们对 E
的唯一了解是 default c-tor
,否则代码无法编译。
一般来说,c-tor 的移动看起来像 Werner Henze 建议的那样。不过我建议你也重置指针。
template <typename E>
Node::Node<E>( Node<E> && other ) :
next(std::move(other.next)), // line 1
elem(std::move(other.elem)){ // line 2
// change to NULL for pre C++11
other.next = nullptr; // line 3
}
这是怎么回事?
解释如下:
- 第 1 行 - 我们移动指针。指针不能真正移动。它被复制了。不过保持
std::move
是个好习惯,只为"show the intention"你感动。 - 第 2 行 - 我们移动数据。这里有可能性:
- 如果
E
是movable
class,这步class。 - 如果
E
不是move-able
class,而是copy-able
(最简单的例子是int
),复制 - 如果
E
不是move-able
class,也不是copy-able
。这不会编译。
- 如果
第2行执行后,E
处于valid
状态,但不能使用,因为里面可能有不同的数据。您可以销毁它或分配它。
- 第 2 行 - 这里我们重置指针,因为
d-tor
可能决定用它做一些事情。
备选
最后我会给你 move c-tor
的替代代码 - 使用 swap
.
它可能会更慢,但出于教育目的是可以的。
template <typename E>
Node::Node<E>( Node<E> && other ){
// "this" class is created now.
using std::swap;
swap(next, other.next);
swap(elem, elem);
}
最后的注释:
这里不需要{}
:
private:
E elem{}; //datatype independent element
这就够了:
private:
E elem; //datatype independent element