按 unique_ptr 或按值传递对象以及如何实现
Passing object by unique_ptr or by value and how to implement
我有一个案例,我不确定是否应该使用 unique_ptr
或按值传递对象。
假设我有 class A,它有一个向量 class B,Class C 也有一个向量 class B。每次我将 B 对象添加到 class C 中的 Vector 时,它应该从 Class C 的向量中删除,反之亦然。当对象 C 被销毁时,B Vector class 中的所有对象都应添加到 class A
中的 B vector
class B {
public:
B();
virtual ~B();
};
class A {
C & c;
std::vector<B> bs;
public:
A(C & c ): c(c){};
virtual ~A();
void add(B b){
bs.push_back(b);
c.remove(b);
}
void remove(B b){
bs.erase(std::remove(bs.begin(), bs.end(), b), bs.end());
}
};
class C {
public:
A & a;
std::vector<B> bs;
C(A & a): a(a) {
};
virtual ~C(){
for (B b : bs) {
a.add(b);
remove(b);
}
}
void add(B b){
bs.push_back(b);
a.remove(b);
}
void remove(B b){
bs.erase(std::remove(bs.begin(), bs.end(), b), bs.end());
}
};
我的问题:
- 在这种情况下使用指针更好吗?我应该始终为 B 拥有一个独特的对象!换句话说,如果两个 b 对象的内容不同,它们仍然不同,因为内存中的地址不同。
- 我想借助 smart_pointers 在 C++ 11 中编写此代码!哪种类型更好
shared_ptr
或 unique_ptr
? B 对象永远不会被两个对象拥有,它始终只有一个所有者,所以我猜 unique_ptr
更好,但我不确定。
- 如何使用 unique_ptr 编写上面的代码?
如果复制构造B
成本高昂,那么(智能)指针可能是个好主意(重新设计应用程序逻辑可能是另一种解决方案),
如果我理解正确,给定的 B
实例总是由单个所有者(A
或 C
)操纵。 std::unique_ptr
因此是一个合理的选择,
尝试以下实现。我还没有编译它,但我想你会得到大致的想法:)
.
class B {
public:
B();
virtual ~B();
};
class A {
C & c;
std::vector<std::unique_ptr<B>> bs;
public:
A(C & c ): c(c){};
virtual ~A();
// http://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/
// (c) Passing unique_ptr by value means "sink."
void add(std::unique_ptr<B> b){
c.remove(b); // release the poiner from the other container
bs.emplace_back(b.get()); // emplace the pointer in the new one
b.release(); // emplacement successful. release the pointer
}
// http://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/
// (d) Passing unique_ptr by reference is for in/out unique_ptr parameters.
void remove(std::unique_ptr<B>& b){
// @todo check that ther returned pointer is != bs.end()
std::find(bs.begin(), bs.end(), b)->release(); // first release the pointer
bs.erase(std::remove(bs.begin(), bs.end(), b), bs.end()); // then destroy its owner
}
};
class C {
public:
A & a;
std::vector<std::unique_ptr<B>> bs;
C(A & a): a(a) {
};
virtual ~C(){
for (auto&& b : bs) {
a.add(b);
// a is going to call this->remove()...
// unless calling this->remove() from "a"
// while this is being destroyed is Undefined Behavior (tm)
// I'm not sure :)
}
}
// http://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/
// (c) Passing unique_ptr by value means "sink."
void add(std::unique_ptr<B> b){
c.remove(b); // release the poiner from the other container
bs.emplace_back(b.get()); // emplace the pointer in the new one
b.release(); // emplacement successful. release the pointer
}
// http://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/
// (d) Passing unique_ptr by reference is for in/out unique_ptr parameters.
void remove(std::unique_ptr<B>& b){
// @todo check that ther returned pointer is != bs.end()
std::find(bs.begin(), bs.end(), b)->release(); // first release the pointer
bs.erase(std::remove(bs.begin(), bs.end(), b), bs.end()); // then destroy its owner
}
};
如果必须的话,我只会使用 unique_ptr
。您可能更愿意将 B
设置为只能移动的类型(如 unique_ptr
)以限制所有权。
如果 B
的移动成本很高,或者防止复制 B
不切实际,则使用 unique_ptr
,但请注意,您需要为动态内存分配付费.
以下是您如何在受您的代码启发的示例中使用仅移动 B
。如果您改用 unique_ptr
,它的工作原理应该完全相同:
struct B {
B();
B(B&&) = default; // Explicitly default the
B& operator=(B&&) = default; // move functions.
B(const B&) = delete; // Delete copy functions - Not strictly
B& operator=(const B&) = delete; // necessary but just to be explicit.
};
struct A {
std::vector<B> bs;
void add(B b){
bs.push_back(std::move(b));
}
B remove(std::vector<B>::iterator itr){
B tmp = std::move(*itr);
bs.erase(itr);
return tmp;
}
};
struct C {
A& a;
std::vector<B> bs;
C(A& a) : a(a) {}
~C(){
for (auto& b : bs) {
a.add(std::move(b));
}
} // bs will be deleted now anyway, no need to remove the dead objects
void add(B b){
bs.push_back(std::move(b));
}
B remove(std::vector<B>::iterator itr){
auto tmp = std::move(*itr);
bs.erase(itr);
return tmp;
}
};
int main() {
A a;
C c(a);
a.add(B());
auto tmp = a.remove(a.bs.begin());
c.add(std::move(tmp));
}
我有一个案例,我不确定是否应该使用 unique_ptr
或按值传递对象。
假设我有 class A,它有一个向量 class B,Class C 也有一个向量 class B。每次我将 B 对象添加到 class C 中的 Vector 时,它应该从 Class C 的向量中删除,反之亦然。当对象 C 被销毁时,B Vector class 中的所有对象都应添加到 class A
中的 B vectorclass B {
public:
B();
virtual ~B();
};
class A {
C & c;
std::vector<B> bs;
public:
A(C & c ): c(c){};
virtual ~A();
void add(B b){
bs.push_back(b);
c.remove(b);
}
void remove(B b){
bs.erase(std::remove(bs.begin(), bs.end(), b), bs.end());
}
};
class C {
public:
A & a;
std::vector<B> bs;
C(A & a): a(a) {
};
virtual ~C(){
for (B b : bs) {
a.add(b);
remove(b);
}
}
void add(B b){
bs.push_back(b);
a.remove(b);
}
void remove(B b){
bs.erase(std::remove(bs.begin(), bs.end(), b), bs.end());
}
};
我的问题:
- 在这种情况下使用指针更好吗?我应该始终为 B 拥有一个独特的对象!换句话说,如果两个 b 对象的内容不同,它们仍然不同,因为内存中的地址不同。
- 我想借助 smart_pointers 在 C++ 11 中编写此代码!哪种类型更好
shared_ptr
或unique_ptr
? B 对象永远不会被两个对象拥有,它始终只有一个所有者,所以我猜unique_ptr
更好,但我不确定。 - 如何使用 unique_ptr 编写上面的代码?
如果复制构造
B
成本高昂,那么(智能)指针可能是个好主意(重新设计应用程序逻辑可能是另一种解决方案),如果我理解正确,给定的
B
实例总是由单个所有者(A
或C
)操纵。std::unique_ptr
因此是一个合理的选择,尝试以下实现。我还没有编译它,但我想你会得到大致的想法:)
.
class B {
public:
B();
virtual ~B();
};
class A {
C & c;
std::vector<std::unique_ptr<B>> bs;
public:
A(C & c ): c(c){};
virtual ~A();
// http://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/
// (c) Passing unique_ptr by value means "sink."
void add(std::unique_ptr<B> b){
c.remove(b); // release the poiner from the other container
bs.emplace_back(b.get()); // emplace the pointer in the new one
b.release(); // emplacement successful. release the pointer
}
// http://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/
// (d) Passing unique_ptr by reference is for in/out unique_ptr parameters.
void remove(std::unique_ptr<B>& b){
// @todo check that ther returned pointer is != bs.end()
std::find(bs.begin(), bs.end(), b)->release(); // first release the pointer
bs.erase(std::remove(bs.begin(), bs.end(), b), bs.end()); // then destroy its owner
}
};
class C {
public:
A & a;
std::vector<std::unique_ptr<B>> bs;
C(A & a): a(a) {
};
virtual ~C(){
for (auto&& b : bs) {
a.add(b);
// a is going to call this->remove()...
// unless calling this->remove() from "a"
// while this is being destroyed is Undefined Behavior (tm)
// I'm not sure :)
}
}
// http://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/
// (c) Passing unique_ptr by value means "sink."
void add(std::unique_ptr<B> b){
c.remove(b); // release the poiner from the other container
bs.emplace_back(b.get()); // emplace the pointer in the new one
b.release(); // emplacement successful. release the pointer
}
// http://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/
// (d) Passing unique_ptr by reference is for in/out unique_ptr parameters.
void remove(std::unique_ptr<B>& b){
// @todo check that ther returned pointer is != bs.end()
std::find(bs.begin(), bs.end(), b)->release(); // first release the pointer
bs.erase(std::remove(bs.begin(), bs.end(), b), bs.end()); // then destroy its owner
}
};
如果必须的话,我只会使用 unique_ptr
。您可能更愿意将 B
设置为只能移动的类型(如 unique_ptr
)以限制所有权。
如果 B
的移动成本很高,或者防止复制 B
不切实际,则使用 unique_ptr
,但请注意,您需要为动态内存分配付费.
以下是您如何在受您的代码启发的示例中使用仅移动 B
。如果您改用 unique_ptr
,它的工作原理应该完全相同:
struct B {
B();
B(B&&) = default; // Explicitly default the
B& operator=(B&&) = default; // move functions.
B(const B&) = delete; // Delete copy functions - Not strictly
B& operator=(const B&) = delete; // necessary but just to be explicit.
};
struct A {
std::vector<B> bs;
void add(B b){
bs.push_back(std::move(b));
}
B remove(std::vector<B>::iterator itr){
B tmp = std::move(*itr);
bs.erase(itr);
return tmp;
}
};
struct C {
A& a;
std::vector<B> bs;
C(A& a) : a(a) {}
~C(){
for (auto& b : bs) {
a.add(std::move(b));
}
} // bs will be deleted now anyway, no need to remove the dead objects
void add(B b){
bs.push_back(std::move(b));
}
B remove(std::vector<B>::iterator itr){
auto tmp = std::move(*itr);
bs.erase(itr);
return tmp;
}
};
int main() {
A a;
C c(a);
a.add(B());
auto tmp = a.remove(a.bs.begin());
c.add(std::move(tmp));
}