c++ - 如何将指针语义添加到 C++ STL 中?

标签 c++ vector stl deque

我最近正在研究 C++ STL,我将讨论一个使用 deque 的示例。请注意,deque 只是一个示例,我们还可以使用 vector 或其他。

背景

最小的可重现示例是一个简单的多队列生产者-消费者问题。考虑一个可以自己洗衣服的智能洗衣机,以及一个可以从洗衣机中取出衣服并烘干的智能烘干机。洗衣机可以被认为是多件未洗衣服的队列,而烘干机可以被认为是已洗衣服的队列。

Clothes类成为衣服的单位。生产者将不断生成衣服并将它们添加到洗衣机队列中。当洗衣机洗完一件衣服后,它会将其取出并添加到烘干机队列中。

问题

如果我们要在 C 语言中执行此操作,则使用指针 (malloc()) 和链表会很简单。通过移动指针,我们可以保证不会分配重复的Clothes。完成后,我们可以简单地调用 free()

我们可以在 C++ STL 中做同样的事情吗?实现这一目标的推荐方法是什么?

我尝试过什么以及什么让我感到困惑

我进行了一些测试,发现 C++ STL 自己处理内存分配和释放,这让我很困惑。

例如,(假设我们在本例中使用deque):

std::deque<Clothes> washer = {...}; // only 1 object 
std::deque<Clothes> dryer; // empty

// case 1: copy constructor is invoked, 2 memory locations occupied
Clothes c = washer.front();

washer.pop_front(); // destructor is invoked, I think this corresponds to the original Clothes

上面调用了复制构造函数并产生 1 个重复的拷贝。操作 pop_front() 隐式调用 Clothes 对象的析构函数。但它不会影响c,因为它是由复制构造函数构造的。现在,衣服的数量仍然是一件。

// case 2: copy constructor is not invoked
Clothes &c = washer.front();

washer.pop_front(); // destructor is invoked again, but there is only one Clothes object

上面的代码通过引用获取了washer中的第一个对象,并且没有调用复制构造函数。我假设现在仍然只有一个 Clothes 对象。但是,当我们调用 pop_front() 时,会调用 Clothes 的析构函数。我尝试通过 c.val 访问 Clothes 对象中的某些字段(假设 valClothes 中的一个字段) ,我发现我仍然可以访问它,这意味着 Clothes c 没有被破坏。这就是为什么我很困惑。为什么调用析构函数,以及哪个 Clothes 对象被析构?

我的想法

我认为情况 1 可能是正确的方法,但情况 2 似乎也是正确的,尽管发生了一些意想不到的事情。

最佳答案

代码中的问题:

您是正确的,在情况 1 中,Cloths 的拷贝被 build 。 你也是正确的,在情况 2 c 中没有复制。
然而,在情况2 c是对已破坏对象的悬空引用,访问它会导致 undefined behavior 。这意味着任何事情都可能发生,包括“工作”代码的出现。

解决方案:

C++ 提供智能指针。
您可以使用 std::shared_ptr<Clothes> 作为容器中的元素。这将避免同时复制 Clothes对象并具有悬空引用。
一个std::shared_ptr自动管理对象(在本例中为 Clothes 类型)的生命周期。当不再需要时它将被释放(这是通过为每个对象保留引用计数来完成的)。
注意推荐的创建方式shared_ptr s 是通过 std::make_shared .

#include <deque>
#include <memory>

class Clothes 
{ 
    // ...
};

int main() 
{
    std::deque<std::shared_ptr<Clothes>> washer = { std::make_shared<Clothes>() }; 
    std::deque<std::shared_ptr<Clothes>> dryer;

    auto c = washer.front();        
    washer.pop_front();             
    dryer.push_back(c);
}

最后请注意,还有 std::unique_ptr ,它支持单一所有者且无复制(仅移动)。然而在这种情况下,在我看来std::shared_ptr使用起来更直接。如果你想使用std::unique_ptr ,它应该是这样的:

#include <deque>
#include <memory>

class Clothes 
{ 
    // ...
};

int main() 
{
    std::deque<std::unique_ptr<Clothes>> washer;
    washer.push_back(std::make_unique<Clothes>());
    std::deque<std::unique_ptr<Clothes>> dryer;

    auto c = std::move(washer.front());
    washer.pop_front();
    dryer.push_back(std::move(c));
}

关于c++ - 如何将指针语义添加到 C++ STL 中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76809733/

相关文章:

c++ - 如何通过malloc为队列数组分配内存?

C++ 代码不按预期返回 vector 并在转换时抛出错误

javascript - 旋转 HTML Canvas 中的点

c++ - 从给定索引上的 vector 中删除元素,顺序无关紧要

c++ - 将父类设为私有(private),将祖 parent 设为公有类

c++ - 如何在 windowsservercore docker 容器中安装 dotnetcore

c++ - 在 TTreeView 上点击 TListView(在 TForm 上)触发 TTreeView OnChange 事件

c++ - 同时对两个 vector (键/值)进行排序的最快方法?

c++ - 如何编写一个同时使用迭代器和索引计数器的 for 循环?

c++ - 如何找到文本文档中最长的单词?