首页 > 解决方案 > 将使用 PIMPL 习语的类存储在 std::vector 中

问题描述

我正在编写一个应用程序,该应用程序需要将使用 PIMPL 习惯用法的类的对象存储在std::vector. 因为该类用于std::unique_ptr存储指向其实现的指针并且std::unique_ptr不可复制,所以该类本身不可复制。std::vector在这种情况下应该仍然可以工作,因为该类仍然是可移动的。

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

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

测试.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;
};

测试.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();
}

主.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.

标签: c++c++11vectormove-semanticspimpl-idiom

解决方案


将它们添加Test(Test&&) noexcept;到您的 cpp 文件中。Test& operator=(Test&&) noexcept;=default

您可能应该在使用Test(const int value)时明确表示。

至少在现代 gcc/clang=default中,您可以在标题中移动 ctor。您不能这样做,operator=因为它可以删除左侧指针,也不能删除零参数构造函数(与构造默认删除器有关?)或析构函数(必须调用默认删除器)。


推荐阅读