在 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
这引出了两个问题...
为什么我明确使用了 emplace_back
却试图使用复制构造函数?
我怎样才能让它编译无误?该对象是可移动的,因此根据标准,它应该能够存储在 std::vector
.
中
在您的 cpp 文件中添加 Test(Test&&) noexcept;
和 Test& operator=(Test&&) noexcept;
,然后 =default
。
你可能应该 Test(const int value)
明确说明。
至少在 modern gcc/clang 中,您可以 =default
在页眉中移动构造函数。您不能对 operator=
执行此操作,因为它可以删除左侧指针,也不能删除零参数构造函数(与构造默认删除器有关?)或析构函数(必须调用默认删除器)。
我正在编写一个需要存储 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
这引出了两个问题...
为什么我明确使用了
emplace_back
却试图使用复制构造函数?我怎样才能让它编译无误?该对象是可移动的,因此根据标准,它应该能够存储在
中std::vector
.
在您的 cpp 文件中添加 Test(Test&&) noexcept;
和 Test& operator=(Test&&) noexcept;
,然后 =default
。
你可能应该 Test(const int value)
明确说明。
至少在 modern gcc/clang 中,您可以 =default
在页眉中移动构造函数。您不能对 operator=
执行此操作,因为它可以删除左侧指针,也不能删除零参数构造函数(与构造默认删除器有关?)或析构函数(必须调用默认删除器)。