- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
动机
C++ 核心指南推荐使用 dynamic_cast
当“类层次结构导航是不可避免的”时。这会触发 clang-tidy 抛出以下错误:Do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead [cppcoreguidelines-pro-type-static-cast-downcast]
.
指导方针继续说:
Note:
Like other casts,
dynamic_cast
is overused. Prefervirtual
functionsto casting. Prefer static polymorphism to hierarchy navigation whereit is possible (no run-time resolution necessary) and reasonablyconvenient.
enum
命名
Kind
嵌套在我的基类中,并执行了
static_cast
基于它的种类。阅读 C++ 核心指南,“...即便如此,根据我们的经验,诸如“我知道我在做什么”的情况仍然是一个已知的错误来源。”建议我不应该这样做。通常,我没有任何
virtual
函数,因此 RTTI 不存在以使用
dynamic_cast
(例如,我会得到
error: 'Base_discr' is not polymorphic
)。我可以随时添加
virtual
功能,但这听起来很傻。该指南还说在考虑使用我与
Kind
一起使用的判别方法之前先进行基准测试。 .
enum class Kind : unsigned char {
A,
B,
};
class Base_virt {
public:
Base_virt(Kind p_kind) noexcept : m_kind{p_kind}, m_x{} {}
[[nodiscard]] inline Kind
get_kind() const noexcept {
return m_kind;
}
[[nodiscard]] inline int
get_x() const noexcept {
return m_x;
}
[[nodiscard]] virtual inline int get_y() const noexcept = 0;
private:
Kind const m_kind;
int m_x;
};
class A_virt final : public Base_virt {
public:
A_virt() noexcept : Base_virt{Kind::A}, m_y{} {}
[[nodiscard]] inline int
get_y() const noexcept final {
return m_y;
}
private:
int m_y;
};
class B_virt : public Base_virt {
public:
B_virt() noexcept : Base_virt{Kind::B}, m_y{} {}
private:
int m_y;
};
static void
virt_static_cast(benchmark::State& p_state) noexcept {
auto const a = A_virt();
Base_virt const* ptr = &a;
for (auto _ : p_state) {
benchmark::DoNotOptimize(static_cast<A_virt const*>(ptr)->get_y());
}
}
BENCHMARK(virt_static_cast);
static void
virt_static_cast_check(benchmark::State& p_state) noexcept {
auto const a = A_virt();
Base_virt const* ptr = &a;
for (auto _ : p_state) {
if (ptr->get_kind() == Kind::A) {
benchmark::DoNotOptimize(static_cast<A_virt const*>(ptr)->get_y());
} else {
int temp = 0;
}
}
}
BENCHMARK(virt_static_cast_check);
static void
virt_dynamic_cast_ref(benchmark::State& p_state) {
auto const a = A_virt();
Base_virt const& reff = a;
for (auto _ : p_state) {
benchmark::DoNotOptimize(dynamic_cast<A_virt const&>(reff).get_y());
}
}
BENCHMARK(virt_dynamic_cast_ref);
static void
virt_dynamic_cast_ptr(benchmark::State& p_state) noexcept {
auto const a = A_virt();
Base_virt const& reff = a;
for (auto _ : p_state) {
benchmark::DoNotOptimize(dynamic_cast<A_virt const*>(&reff)->get_y());
}
}
BENCHMARK(virt_dynamic_cast_ptr);
static void
virt_dynamic_cast_ptr_check(benchmark::State& p_state) noexcept {
auto const a = A_virt();
Base_virt const& reff = a;
for (auto _ : p_state) {
if (auto ptr = dynamic_cast<A_virt const*>(&reff)) {
benchmark::DoNotOptimize(ptr->get_y());
} else {
int temp = 0;
}
}
}
BENCHMARK(virt_dynamic_cast_ptr_check);
class Base_discr {
public:
Base_discr(Kind p_kind) noexcept : m_kind{p_kind}, m_x{} {}
[[nodiscard]] inline Kind
get_kind() const noexcept {
return m_kind;
}
[[nodiscard]] inline int
get_x() const noexcept {
return m_x;
}
private:
Kind const m_kind;
int m_x;
};
class A_discr final : public Base_discr {
public:
A_discr() noexcept : Base_discr{Kind::A}, m_y{} {}
[[nodiscard]] inline int
get_y() const noexcept {
return m_y;
}
private:
int m_y;
};
class B_discr : public Base_discr {
public:
B_discr() noexcept : Base_discr{Kind::B}, m_y{} {}
private:
int m_y;
};
static void
discr_static_cast(benchmark::State& p_state) noexcept {
auto const a = A_discr();
Base_discr const* ptr = &a;
for (auto _ : p_state) {
benchmark::DoNotOptimize(static_cast<A_discr const*>(ptr)->get_y());
}
}
BENCHMARK(discr_static_cast);
static void
discr_static_cast_check(benchmark::State& p_state) noexcept {
auto const a = A_discr();
Base_discr const* ptr = &a;
for (auto _ : p_state) {
if (ptr->get_kind() == Kind::A) {
benchmark::DoNotOptimize(static_cast<A_discr const*>(ptr)->get_y());
} else {
int temp = 0;
}
}
}
BENCHMARK(discr_static_cast_check);
我是基准测试的新手,所以我真的不知道我在做什么。我小心翼翼地确保
virtual
和判别版本具有相同的内存布局,并尽我所能防止优化。我选择了优化级别
O1
因为任何更高的东西似乎都没有代表性。
discr
代表歧视或标记。
virt
代表
virtual
这是我的结果:
dynamic_cast
好像是
correct低头的答案。但是,您仍然需要知道您正在向下转型并拥有一个
virtual
功能。在很多情况下,你不知道没有歧视,比如
kind
或
tag
派生类是什么。 (4) 在我已经要检查什么的情况下
kind
我正在查看的对象,我是否应该仍然使用
dynamic_cast
?这不是两次检查同一件事吗? (5) 在没有
tag
的情况下,是否有合理的方法可以做到这一点? ?
class
等级制度:
class Expr {
public:
enum class Kind : unsigned char {
Int_lit_expr,
Neg_expr,
Add_expr,
Sub_expr,
};
[[nodiscard]] Kind
get_kind() const noexcept {
return m_kind;
}
[[nodiscard]] bool
is_unary() const noexcept {
switch(get_kind()) {
case Kind::Int_lit_expr:
case Kind::Neg_expr:
return true;
default:
return false;
}
}
[[nodiscard]] bool
is_binary() const noexcept {
switch(get_kind()) {
case Kind::Add_expr:
case Kind::Sub_expr:
return true;
default:
return false;
}
}
protected:
explicit Expr(Kind p_kind) noexcept : m_kind{p_kind} {}
private:
Kind const m_kind;
};
class Unary_expr : public Expr {
public:
[[nodiscard]] Expr const*
get_expr() const noexcept {
return m_expr;
}
protected:
Unary_expr(Kind p_kind, Expr const* p_expr) noexcept :
Expr{p_kind},
m_expr{p_expr} {}
private:
Expr const* const m_expr;
};
class Binary_expr : public Expr {
public:
[[nodiscard]] Expr const*
get_lhs() const noexcept {
return m_lhs;
}
[[nodiscard]] Expr const*
get_rhs() const noexcept {
return m_rhs;
}
protected:
Binary_expr(Kind p_kind, Expr const* p_lhs, Expr const* p_rhs) noexcept :
Expr{p_kind},
m_lhs{p_lhs},
m_rhs{p_rhs} {}
private:
Expr const* const m_lhs;
Expr const* const m_rhs;
};
class Add_expr : public Binary_expr {
public:
Add_expr(Expr const* p_lhs, Expr const* p_rhs) noexcept :
Binary_expr{Kind::Add_expr, p_lhs, p_rhs} {}
};
现在在
main()
:
int main() {
auto const add = Add_expr{nullptr, nullptr};
Expr const* const expr_ptr = &add;
if (expr_ptr->is_unary()) {
auto const* const expr = static_cast<Unary_expr const* const>(expr_ptr)->get_expr();
} else if (expr_ptr->is_binary()) {
// Here I use a static down cast after checking it is valid
auto const* const lhs = static_cast<Binary_expr const* const>(expr_ptr)->get_lhs();
// error: cannot 'dynamic_cast' 'expr_ptr' (of type 'const class Expr* const') to type 'const class Binary_expr* const' (source type is not polymorphic)
// auto const* const rhs = dynamic_cast<Binary_expr const* const>(expr_ptr)->get_lhs();
}
}
<source>:99:34: warning: do not use static_cast to downcast from a base to a derived class [cppcoreguidelines-pro-type-static-cast-downcast]
auto const* const expr = static_cast<Unary_expr const* const>(expr_ptr)->get_expr();
^
我并不总是需要转换到
Add_expr
.例如,我可以有一个函数打印出任何
Binary_expr
.只需将其强制转换为
Binary_expr
获取
lhs
和
rhs
.要获取运算符的符号(例如“-”或“+”...),它可以打开
kind
.我不明白
dynamic_cast
会在这里帮助我,而且我也没有可以使用的虚函数
dynamic_cast
在。
get_kind()
virtual
,这似乎是一个很好的解决方案。但是,我现在为
vtbl_ptr
携带了大约 8 个字节。而不是标签的字节。从
class
实例化的对象es 源自
Expr
将远远超过任何其他对象类型。 (6) 现在是跳过
vtbl_ptr
的好时机吗?或者我应该更喜欢
dynamic_cast
的安全性?
最佳答案
如果您在编译时知道实例的类型,您可能对这里的 Curious Recursing Template Pattern 感兴趣,以避免对虚方法的需要
template <typename Impl>
class Base_virt {
public:
Base_virt(Kind p_kind) noexcept : m_kind{p_kind}, m_x{} {}
[[nodiscard]] inline Kind
get_kind() const noexcept { return Impl::kind(); }
[[nodiscard]] inline int
get_x() const noexcept {
return m_x;
}
[[nodiscard]] inline int get_y() const noexcept {
return static_cast<const Impl*>(this)->get_y();
}
private:
int m_x;
};
class A_virt final : public Base_virt<A_virt> {
public:
A_virt() noexcept : Base_virt{Kind::A}, m_y{} {}
[[nodiscard]] inline static Kind kind() { return Kind::A; }
[[nodiscard]] inline int
get_y() const noexcept final {
return m_y;
}
private:
int m_y;
};
// Copy/paste/rename for B_virt
在这种情况下,根本不需要 dynamic_cast,因为在编译时一切都是已知的。您正在失去存储指向
Base_virt
的指针的可能性。 (除非您创建
BaseTag
派生自
Base_virt
的基类)
template <typename Impl>
static void
crtp_cast_check(benchmark::State& p_state) noexcept {
auto const a = A_virt();
Base_virt<Impl> const* ptr = &a;
for (auto _ : p_state) {
benchmark::DoNotOptimize(ptr->get_y());
}
}
BENCHMARK(crtp_static_cast_check<A_virt>);
这很可能被编译为对
for(auto _ : p_state) b::dno(m_y)
的海峡调用。 .
BaseTag
方法,它看起来像:
class BaseTag { virtual Kind get_kind() const = 0; };
// No virtual destructor here, since you aren't supposed to manipulate instance via this type
template <typename Impl>
class Base_virt : BaseTag { ... same as previous definition ... };
// Benchmark method become
void virt_bench(BaseTag & base) {
// This is the only penalty with a virtual method:
switch(base.get_kind()) {
case Kind::A : static_cast<A_virt&>(base).get_y(); break;
case Kind::B : static_cast<B_virt&>(base).get_y(); break;
...etc...
default: assert(false); break; // At least you'll get a runtime error if you forget to update this table for new Kind
}
// In that case, there is 0 advantage not to make get_y() virtual, but
// if you have plenty of "pseudo-virtual" method, it'll become more
// interesting to consult the virtual table only once for get_kind
// instead of for each method
}
template <typename Class>
void static_bench(Class & inst) {
// Lame code:
inst.get_y();
}
A_virt a;
B_virt b;
virt_bench(a);
virt_bench(b);
// vs
static_bench(a);
static_bench(b);
抱歉上面的伪代码,但你会明白的。
关于c++ - 如何正确使用 "C++ Core Guidelines: C.146: Use dynamic_cast where class hierarchy navigation is unavoidable",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63520261/
主要思想是将 EF Core nuget 包添加到 .NET Core 库项目,然后在一堆应用程序(例如 ASP.NET Core、Win 服务、控制台应用程序)中使用该库,而无需在每个应用程序中配置
我想要实现的是编写一个简单的.net核心后台工作程序(.net core 3.1)的代码,在该工作程序作为Windows服务运行时,我在其中将数据写入SQL Server数据库(通过EF Core 3
关于 .Net Core SDK download page 二进制文件有什么用?它与安装程序有何不同? 最佳答案 二进制文件是 .NET Core 的编译代码。它们拥有运行 .NET Core 所需
.NET Core 和 Entity Framework Core 之间的区别?我们可以在 .NET Core 中使用 Entity Framework Core 吗?两者都有什么优势? 最佳答案 E
.NET Core 和 ASP.NET Core 到底有什么区别? 它们是相互排斥的吗?我听说 ASP.NET Core 是基于 .NET Core 构建的,但它也可以基于完整的 .NET 框架构建。
我对 ASP.NET Core 开发完全陌生。我正在尝试使用单个模型和 mysql 创建一个简单的 asp.net core Web api 来存储模型数据,然后我想使用 Swagger 将其作为 R
.NET Core 和 Entity Framework Core 之间的区别?我们可以在 .NET Core 中使用 Entity Framework Core 吗?两者都有什么优势? 最佳答案 E
好吧,作为一个新的 .net 开发生态系统,我有点迷失在核心工具、版本等方面。 有人可以解释我之间的区别吗 VS 2015 核心工具预览版 x - See here .NET Core/SDK 与否
我已阅读有关如何通过信号器核心集线器从后台服务向客户端发送通知的文档。如何从客户端接收到后台服务的通知? 后台服务应该只是一个单例。 public class Startup { public
关闭。这个问题是opinion-based .它目前不接受答案。 想改善这个问题吗?更新问题,以便可以通过 editing this post 用事实和引文回答问题. 4年前关闭。 Improve t
非常简单的问题: 我正在尝试创建一个像这样的谓词构建器: var predicate = PredicateBuilder.False(); 但似乎在Net Core和EF Core中不可用。
在 .NET Core 自包含应用程序 中...我们需要在 project.json 中指定运行时 (RID) 我们希望我们的应用程序针对...发布为什么会这样? .NET Core 是跨平台的,与我
如何用 iCloud Core Data 替换我现有的 Core Data?这是我的持久商店协调员: lazy var persistentStoreCoordinator: NSPersistent
关闭。这个问题是opinion-based 。目前不接受答案。 想要改进这个问题吗?更新问题,以便 editing this post 可以用事实和引文来回答它。 . 已关闭 2 年前。 Improv
今天我正在学习新的 ASP.net 核心 API 3.1,我想将我的旧网站从 MVC4 转移到 Web API。除了一件事,一切都很好。数据库连接。在我的旧网站中,我为每个客户端(10/15 数据库)
我在 Visual Studio 2015 Update 3 和 .NET Core 1.0 中工作。我有一个 .NETCoreApp v1.0 类型的 Web API 项目。当我添加一个 .NET
我一直在尝试遵循 Ben Cull ( http://benjii.me/2016/06/entity-framework-core-migrations-for-class-library-proj
当我打开我的 vs 代码程序时,我收到以下消息: 无法找到 .NET Core SDK。 .NET Core 调试将不会启用。确保 .NET Core SDK 已安装并且在路径上。 如果我安装甚至卸载
我偶然发现了一个非常奇怪的问题。每当 Web 应用程序启动时,dotnet.exe 都会使用相当多的内存(大约 300M)。然而,当它触及某些部分时(我感觉这与 EF Core 使用有关),它会在短时
ASP.NET Core Web (.NET Core) 与 ASP.NET Core Web (.NET Framework) 有什么区别? .NET Framework 是否提供 similar
我是一名优秀的程序员,十分优秀!