比较C++中move和智能指针的习惯?
Compare the habits between move and smart pointer in C++?
在C++11/14中,对象可以通过move
或smark指针来传递。
(1) 这是 move
的示例:
class MoveClass {
private:
int *tab_;
int alloc_;
void Reset() {
tab_ = nullptr;
alloc_ = 0;
}
void Release() {
if (tab_) delete[] tab_;
tab_ = nullptr;
alloc_ = 0;
}
public:
MoveClass() : tab_(nullptr), alloc_(0) {}
~MoveClass() {
Release();
}
MoveClass(MoveClass && other) : tab_( other.tab_ ), alloc_( other.alloc_ ) {
other.Reset();
}
MoveClass & operator=(MoveClass && other) {
if (this == &other) return *this;
std::swap(tab_, other.tab_);
std::swap(alloc_, other.alloc_);
return *this;
}
void DoSomething() { /*...*/ }
};
当我们使用这个可移动的MoveClass
时,我们可以这样写代码:
int main() {
MoveClass a;
a.DoSomething(); // now a has some memory resource
MoveClass b = std::move(a); // move a to b
return 0;
}
总是写move-constructor/move-operator=很无聊,有时候用shared_ptr/unique_ptr也是一样的效果,到处都是java,reference/pointer
(2) 下面是例子:
class NoMoveClass {
private:
int *tab_;
int alloc_;
void Release() {
if (tab_) delete[] tab_;
tab_ = nullptr;
alloc_ = 0;
}
public:
NoMoveClass() : tab_(nullptr), alloc_(0) {}
~NoMoveClass() {
Release();
}
MoveClass(MoveClass && other) = delete;
MoveClass & operator=(MoveClass && other) = delete;
void DoSomething() { /*...*/ }
};
我们可以这样使用:
int main() {
std::shared_ptr<NoMoveClass> a(new NoMoveClass());
a->DoSomething();
std::shared_ptr<NoMoveClass> b = a; // also move a to b by copy pointer.
return 0;
}
总是使用第2个是个好习惯吗?
为什么很多库,STL使用第一个,而不是第一个?
Always write move-constructor/move-operator= is boring
您几乎从不需要编写自己的移动constructor/assignment,因为(正如您提到的)C++ 为您提供了许多基本的资源管理器——智能指针,容器、智能锁等
通过依赖 class 中的那些 ,您可以启用默认的移动操作,从而实现最小的代码大小和正确的语义:
class MoveClass {
private:
std::vector<int> data;
public:
void DoSomething() { /*...*/ }
};
现在您可以像在 (1) 中那样使用您的 class 或作为其他 classes 中的成员,您可以确定它有移动语义,你用尽可能少的代码完成了它。
关键是通常只需要为最低级别的 classes 实现移动操作,这些可能已经被 STL 覆盖,或者如果需要一些奇怪的特定行为 - 这两种情况都应该是罕见且不会导致 "Always writing move-constructor/move-operator=".
另请注意,虽然方法 (1) 不必要地冗长,但 (2) 是不可接受的 - 你有一个资源管理 class 没有完成它的工作,因此您必须将它包装在代码中各处的智能指针中,使其更难理解并最终导致比 (1)[ 更多的代码=28=]
在C++11/14中,对象可以通过move
或smark指针来传递。
(1) 这是 move
的示例:
class MoveClass {
private:
int *tab_;
int alloc_;
void Reset() {
tab_ = nullptr;
alloc_ = 0;
}
void Release() {
if (tab_) delete[] tab_;
tab_ = nullptr;
alloc_ = 0;
}
public:
MoveClass() : tab_(nullptr), alloc_(0) {}
~MoveClass() {
Release();
}
MoveClass(MoveClass && other) : tab_( other.tab_ ), alloc_( other.alloc_ ) {
other.Reset();
}
MoveClass & operator=(MoveClass && other) {
if (this == &other) return *this;
std::swap(tab_, other.tab_);
std::swap(alloc_, other.alloc_);
return *this;
}
void DoSomething() { /*...*/ }
};
当我们使用这个可移动的MoveClass
时,我们可以这样写代码:
int main() {
MoveClass a;
a.DoSomething(); // now a has some memory resource
MoveClass b = std::move(a); // move a to b
return 0;
}
总是写move-constructor/move-operator=很无聊,有时候用shared_ptr/unique_ptr也是一样的效果,到处都是java,reference/pointer
(2) 下面是例子:
class NoMoveClass {
private:
int *tab_;
int alloc_;
void Release() {
if (tab_) delete[] tab_;
tab_ = nullptr;
alloc_ = 0;
}
public:
NoMoveClass() : tab_(nullptr), alloc_(0) {}
~NoMoveClass() {
Release();
}
MoveClass(MoveClass && other) = delete;
MoveClass & operator=(MoveClass && other) = delete;
void DoSomething() { /*...*/ }
};
我们可以这样使用:
int main() {
std::shared_ptr<NoMoveClass> a(new NoMoveClass());
a->DoSomething();
std::shared_ptr<NoMoveClass> b = a; // also move a to b by copy pointer.
return 0;
}
总是使用第2个是个好习惯吗?
为什么很多库,STL使用第一个,而不是第一个?
Always write move-constructor/move-operator= is boring
您几乎从不需要编写自己的移动constructor/assignment,因为(正如您提到的)C++ 为您提供了许多基本的资源管理器——智能指针,容器、智能锁等
通过依赖 class 中的那些 ,您可以启用默认的移动操作,从而实现最小的代码大小和正确的语义:
class MoveClass {
private:
std::vector<int> data;
public:
void DoSomething() { /*...*/ }
};
现在您可以像在 (1) 中那样使用您的 class 或作为其他 classes 中的成员,您可以确定它有移动语义,你用尽可能少的代码完成了它。
关键是通常只需要为最低级别的 classes 实现移动操作,这些可能已经被 STL 覆盖,或者如果需要一些奇怪的特定行为 - 这两种情况都应该是罕见且不会导致 "Always writing move-constructor/move-operator=".
另请注意,虽然方法 (1) 不必要地冗长,但 (2) 是不可接受的 - 你有一个资源管理 class 没有完成它的工作,因此您必须将它包装在代码中各处的智能指针中,使其更难理解并最终导致比 (1)[ 更多的代码=28=]