在 std::vector 中存储使用 PIMPL 习语的 class

Storing a class that uses the PIMPL idiom in a std::vector

我正在编写一个需要存储 class 的对象的应用程序,它在 std::vector 中使用 PIMPL 习语。因为 class 使用 std::unique_ptr 来存储指向其实现的指针并且 std::unique_ptr 不可复制,所以 class 本身不可复制。 std::vector 在这种情况下应该仍然有效,因为 class 仍然是 movable.

为了避免创建副本,我尝试使用 emplace_back 将元素直接构建到 vector 中,但出于某种原因它仍然抱怨它正在尝试调用复制构造函数!

我写了一个简单的例子来演示这个问题。

test.h:

#pragma once

#include <memory>

// Simple test class implemented using the PIMPL (pointer to implementation) idiom
class Test
{
public:
    Test(const int value);
    ~Test();

    void DoSomething();
private:

    // Forward declare implementation struct
    struct Impl;

    // Pointer to the implementation
    std::unique_ptr<Impl> m_impl;
};

test.cpp

#include "test.h"

#include <iostream>

// Implementation struct definition
struct Test::Impl
{
    Impl(const int value)
        : m_value(value)
    {}

    void DoSomething()
    {
        std::cout << "value = " << m_value << std::endl;
    }

private:
    int m_value;
};

// Construct the class and create an instance of the implementation struct
Test::Test(const int value)
    : m_impl(std::make_unique<Impl>(value))
{}

Test::~Test() = default;

// Forward function calls to the implementation struct
void Test::DoSomething()
{
    m_impl->DoSomething();
}

main.cpp:

#include "test.h"

#include <vector>

int main()
{
    std::vector<Test> v;

    // Even though I'm using "emplace_back" it still seems to be invoking the copy constructor!
    v.emplace_back(42);

    return 0;
}

当我尝试编译此代码时出现以下错误:

error C2280: 'Test::Test(const Test &)': attempting to reference a deleted function

这引出了两个问题...

  1. 为什么我明确使用了 emplace_back 却试图使用复制构造函数?

  2. 我怎样才能让它编译无误?该对象是可移动的,因此根据标准,它应该能够存储在 std::vector.

在您的 cpp 文件中添加 Test(Test&&) noexcept;Test& operator=(Test&&) noexcept;,然后 =default

你可能应该 Test(const int value) 明确说明。

至少在 modern gcc/clang 中,您可以 =default 在页眉中移动构造函数。您不能对 operator= 执行此操作,因为它可以删除左侧指针,也不能删除零参数构造函数(与构造默认删除器有关?)或析构函数(必须调用默认删除器)。