咱们一起学C++ 第二百八十三篇之C++容器所有权控制与值存储方式详解

咱们一起学C++ 第二百八十三篇之C++容器所有权控制与值存储方式详解

大家好!C++学习的过程中,容器的使用和管理是非常重要的部分,其中所有权控制以及对象在容器中的存储方式是两个关键知识点。今天咱们就一起来深入探讨这两个方面,希望能和大家共同进步,让我们对C++的理解更上一层楼!

一、容器所有权的灵活控制

在C++编程中,容器与所存储对象之间的所有权关系至关重要。OwnerStack类为我们展示了一种灵活控制所有权的方式。

(一)所有权的默认与修改机制

OwnerStack类通过构造函数的参数和owns()函数来控制容器对所存储对象的所有权。默认情况下,容器拥有它所存储的对象,就像一个“主人”默认拥有自己的物品一样。在Stack(bool own = true): head(0), own(own)构造函数中,own参数的默认值为true,这意味着创建Stack对象时,它默认会销毁自己存储的对象。
但如果我们有特殊需求,也可以修改这个默认行为。比如,当我们创建Stack<AutoCounter> ac2(false);时,通过将构造函数参数设为false,表明ac2这个容器不会销毁它里面存储的对象。这样,ac2就像是一个“临时保管者”,它只负责存放对象,而不负责销毁对象。

(二)所有权对对象销毁的影响

Stack类的析构函数~Stack()中,所有权的状态决定了对象的销毁方式。如果owntrue,容器在销毁时会逐个删除它所存储的对象;如果ownfalse,容器在销毁时不会删除对象,就像“临时保管者”离开时,不会随意处理保管的物品一样。
pop()函数中也是如此,当从容器中弹出对象时,如果容器拥有所有权,弹出操作可能会涉及到对象的销毁;如果不拥有所有权,弹出操作仅仅是将对象从容器中移除,而不会销毁对象。

(三)测试所有权控制

通过OwnerStackTest.cpp中的测试代码,我们可以更直观地理解所有权控制的效果。在这个测试中,创建了两个Stack<AutoCounter>容器,ac默认拥有对象的所有权,而ac2通过构造函数参数设置为不拥有所有权。在添加和弹出对象的过程中,AutoCounter类的对象创建和销毁机制会被触发,从而可以清晰地看到所有权控制对对象生命周期的影响。例如,当从ac2中弹出对象时,由于ac2不拥有对象的所有权,所以对象不会被销毁,而ac容器在销毁时会自动销毁它所拥有的对象。

二、以值存放对象的容器实现

在C++中,除了存储对象指针,以值的方式将对象存放在容器中也是一种常见的需求。ValueStack类为我们展示了这种存储方式的实现。

(一)对象存储与初始化

ValueStack类使用数组T stack[ssize];来存储对象,其中T是模板参数,表示存储对象的类型,ssize是数组的大小,默认值为100。在构造函数Stack(): top(0){}中,top被初始化为0,表示栈为空。
push(const T& x)函数中,当向栈中添加对象时,会调用对象的赋值运算符T::operator=将传入的对象x存储到数组中。这就好比把一个物品原封不动地放进一个盒子里。同时,会检查栈是否已满,如果已满则会根据require函数的设置进行相应处理。

(二)对象的访问与弹出

peek()函数用于查看栈顶对象,但不弹出它,pop()函数则用于弹出栈顶对象。在pop()函数中,先检查栈是否为空,若不为空则返回栈顶对象,并将栈顶指针top减1。需要注意的是,与存储指针的容器不同,以值存放对象时,弹出对象后,对象本身仍然存在,只是不再在栈中。这就像从盒子里拿出一个物品,物品本身还是存在的。

(三)对象拷贝构造的作用

ValueStack类的实现中,用于被包含对象的拷贝构造函数起着重要作用。当使用push()函数添加对象时,对象在栈数组上的存储是通过对象的赋值操作完成的,这依赖于对象的拷贝构造函数。为了更好地理解这个过程,可以创建一个自定义类来测试,例如:

class MyClass {
public:
 MyClass() {
 std::cout << "MyClass constructor" << std::endl;
 }
 MyClass(const MyClass& other) {
 std::cout << "MyClass copy constructor" << std::endl;
 }
 MyClass& operator=(const MyClass& other) {
 std::cout << "MyClass assignment operator" << std::endl;
 return *this;
 }
 ~MyClass() {
 std::cout << "MyClass destructor" << std::endl;
 }
};
int main() {
 ValueStack<MyClass> stack;
 MyClass obj;
 stack.push(obj);
 return 0;
}

在这个示例中,当向ValueStack中添加MyClass对象时,会调用MyClass的拷贝构造函数和赋值运算符,通过观察输出信息可以清晰地看到这个过程。

三、总结

今天我们学习了C++容器的所有权控制和以值存放对象的相关知识。所有权控制让我们可以灵活管理容器与对象之间的关系,避免因对象销毁不当而导致的问题;以值存放对象则为我们提供了一种简单直接的对象存储方式。这些知识对于我们编写高效、可靠的C++代码非常重要。
写作不易,如果这篇文章对你学习C++有所帮助,希望你能点赞支持,也欢迎在评论区分享你的学习心得和疑问。记得关注我的博客,后续我会分享更多C++相关的知识,咱们一起在编程的道路上不断探索、共同进步!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一杯年华@编程空间

原创文章不易,盼您慷慨鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值