- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
最近学习了smart ptrs,我正在尝试编写一个返回unique_ptrs 的工厂函数。阅读了几篇关于将创建时间与明确定义的 ctor 和 dtor 放在同一个 cpp 文件中的文章后,我认为我可以这样做:
// factory.hpp
struct Foo;
std::unique_ptr<Foo> create();
// foo.cpp
struct Foo {
Foo();
~Foo();
Foo(const Foo &);
Foo(Foo &&);
};
std::unique_ptr<Foo> create() {
return make_unique<Foo>();
}
#include "factory.hpp"
int main() {
auto r = create();
return 0;
}
但是我遇到了不完整的类型错误。然后经过几个小时的网络搜索和实验,我意识到我什至不能这样做:
这是经典的 unique_ptr Pimpl 习惯用法。
// A.hpp
struct B;
struct A {
A();
~A();
unique_ptr<B> b;
};
// A.cpp
struct B {};
A::A() = default;
A::~A() = default;
#include "A.hpp"
int main() {
A a; // this is fine since we are doing the Pimpl correctly.
// Now, I can't do this.
auto b = std::move(a.b); // <--- Can't do this.
return 0;
}
为了便于讨论,请忽略 std::move
行毫无意义的事实。我遇到了同样的不完整类型错误。
以上两种情况本质上是一样的。经过一番搜索,我想我明白了错误背后的原因,但我需要你们的一些指示(双关语)和确认。
明确定义创建和销毁函数应该可以解决问题。但对我来说,这很丑陋。其一,默认删除器就可以解决我的问题。另一方面,在我看来我不能将 lambda 用于驱逐舰,因为 lambda 的类型只有编译器知道,而且我无法使用 decltype
进行工厂函数声明。
所以我的问题是:
如果我说的不对请指正。任何指针将不胜感激。
最佳答案
当编译器实例化std::unique_ptr<Foo>
的析构函数时, 编译器必须找到 Foo::~Foo()
并调用它。这意味着 Foo
在 std::unique_ptr<Foo>
处必须是完整类型被摧毁。
这段代码没问题:
struct Foo;
std::unique_ptr<Foo> create();
...只要您不需要调用 std::unique_ptr<Foo>
的析构函数即可!对于返回 std::unique_ptr
的工厂函数对于一个类,该类需要是一个完整的类型。这就是您声明工厂的方式:
#include "foo.hpp"
std::unique_ptr<Foo> create();
您似乎正在使用 std::unique_ptr
实现 pimpl正确。您必须定义 A::~A()
在 B
的位置已完成(在 cpp 文件中)。您必须定义 A::A()
在同一个地方因为B
如果要分配内存并调用其构造函数,则必须是完整的。
所以这很好:
// a.hpp
struct A {
A();
~A();
private:
struct B;
std::unique_ptr<B> b;
};
// a.cpp
struct A::B {
// ...
};
A::A()
: b{std::make_unique<B>()} {}
A::~A() = default;
现在让我们考虑一下(我们假设我没有将 b
设为私有(private)):
int main() {
A a;
auto b = std::move(a.b);
}
这里到底发生了什么?
std::unique_ptr<B>
初始化 b
.b
是一个局部变量,这意味着它的析构函数将在作用域的末尾被调用。B
当 std::unique_ptr<B>
的析构函数时必须是完整类型被实例化。B
是一个不完整的类型,所以我们不能销毁 b
.好的,所以你不能绕过 std::unique_ptr<B>
如果B
是一个不完整的类型。这种限制是有道理的。 pimpl 的意思是“指向实现的指针”。外部代码访问 A
的实现没有意义所以A::b
应该是私有(private)的。如果您必须访问 A::b
那么这不是粉刺,这是别的东西。
如果您真的必须访问 A::b
同时保持 B
的定义隐藏然后有一些解决方法。
std::shared_ptr<B>
.这将以多态方式删除对象,以便 B
当 std::shared_ptr<B>
的析构函数时不需要是完整类型被实例化。它不如std::unique_ptr<B>
快我个人更喜欢避免 std::shared_ptr
除非绝对必要。
std::unique_ptr<B, void(*)(B *)>
.类似于 std::shared_ptr<B>
的方式删除对象。函数指针传递给负责删除的构造。这具有不必要地携带函数指针的开销。
std::unique_ptr<B, DeleteB>
.最快的解决方案。但是,如果您有多个 pimpl(但不是真正的 pimpl)类,这可能会有点烦人,因为您无法定义模板。这就是您的做法:
// a.hpp
struct DeleteB {
void operator()(B *) const noexcept;
};
// a.cpp
void DeleteB::operator()(B *b) const noexcept {
delete b;
}
定义一个自定义删除器可能是最好的选择,但如果我是你,我会找到一种方法来避免需要从类外部访问实现细节。
关于c++ - unique_ptr 和前向声明 : the proper way to code a factory function,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55770004/
有没有办法定义命名参数(不是模型属性)来控制 factory.Maybe 的行为? 例如:我想创建一个命名参数,通过可能条件控制RelatedFactory的创建,我尝试这样做: # factorie
我正在阅读有关创 build 计模式的文章,并且设法将自己完全混淆在工厂、抽象工厂和工厂方法之间。 我在下面发布了一个代码片段。是否有人可以告诉我这是哪一个以及(如果可能)可以对代码进行哪些更改以使其
我正在尝试让 Factory Girl 正常工作,但在运行测试时我不断收到此错误: /Users/dm/.rvm/gems/ruby-1.9.2-p180/gems/activesupport-3.1
有两个公共(public)接口(interface): LayoutInflater.Factory和 LayoutInflater.Factory2在 android sdk 中,但官方文档无法说明
在我们针对 rails 3.1.0 应用程序的 rspec 测试中,我们同时使用了 Factory.build 和 Factory.attributes_for。我们发现,如果我们将 Factory.
我想创建一个 ADF v2 管道来调用 Azure SQL 数据库中的存储过程。存储过程有输入参数并会返回多个结果集(大约 3 个)。我们需要把它提取出来。我们正在尝试加载到 4 个不同文件的 Blo
注意:问题位于帖子末尾。 我已经阅读了有关抽象工厂与工厂方法的其他 stackoverflow 线程。我理解每种模式的意图。不过我不太清楚这个定义。 Factory Method defines an
如何将 :subscriber factory 中的“email”属性值传递给它的关联:authentication 例如: factory :subscriber, :class => Subscr
我正在使用 Factory Boy为我的 Django 应用程序创建测试工厂。我遇到问题的模型是一个非常基本的帐户模型,它与 django 用户身份验证模型(使用 django < 1.5)具有 On
假设我们有一个 I/O 绑定(bind)方法(例如进行数据库调用的方法)。此方法既可以同步运行,也可以异步运行。也就是说, 同步: IOMethod() 异步: BeginIOMethod() End
我正在开发基于 Spring Boot Batch XML 的方法。在此示例中,我开发了一个如下所示的 CommonConfig。不知何故,我想对 Spring Batch 使用基于 XML 的方法,
更新 回答如下。万一链接站点消失,您可以使用 mocha stub 初始状态并防止覆盖,如... require 'mocha' class OrderTest "other_state") e
我有一个非常简单的 Rails 4 应用程序,想使用 Factory Girl 编写一些示例测试。该应用程序适用于一些简单的 rspec 测试(全部通过),但是当我将“factory_girl_rai
我们的要求是从 Blob 存储中获取数据并转换为其他表格形式。这可以通过使用 polybase 的 Sql DW 来实现。在这种情况下,Azure 数据工厂的真正作用是什么? 我知道 Azure 数据
如何解决Spring中Bean的自动连接歧义?我们有一个 Dessert 接口(interface),并且有实现该接口(interface)(Dessert)的三种不同的甜点(Bean)。 今天的甜点
我目前正在使用 RSpec 和 Factory_Bot_Rails gem 来测试应用程序,但我遇到了以下问题。 当使用 factory_bot_rails 版本 5.0.2 gem 时,我的工厂现在
我有下面的简化代码,可以异步获取多个承运人的运费,我想知道是否值得转换为使用异步/等待方法,如果是的话,最好的方法是什么?或者如果它现在工作正常,真的不值得付出努力吗?谢谢。 List> lstTas
我是初学者,正在尝试运行第一个简单的代码。 请帮我解决以下问题。 Error on line 11 of document : The element type "session-factory"
我正在寻求使我的 Rails 测试更快。我只有 520 个测试,但它们在 bash 中运行需要 62 秒,在 Rubymine 中运行需要 82 秒。 作为典型 Controller 测试的示例,我使
我们计划使用 IBM Web Experience Factory 来进行 future 的增强。从项目管理的角度来看我们正在考虑使用Maven。但由于没有在线帮助来同时使用这两个东西,我们无法继续前
我是一名优秀的程序员,十分优秀!