在 std::vector 中存储使用 PIMPL 习惯用法的类

问题描述

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

为了避免创建副本,我尝试使用 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();
}

ma​​in.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= 执行此操作,因为它可以删除左侧指针,也不能删除零参数构造函数(与构造默认删除器有关?)或析构函数(必须调用默认删除器)。>

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...