问题标签 [effective-c++]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
1 回答
96 浏览

c++ - 交换实施:效率和适用范围?

我试图涵盖所有swap功能实现。

swap函数的以下实现中,不需要临时变量来交换两个参数的值:

或者

或者

因此,就使用的内存而言,它比以下内容更有效:

另一方面,swap可以使用以下方式实现:

我正在尝试比较所有现有的实现并了解它们的适用范围。

0 投票
1 回答
881 浏览

c++ - 我是否正确理解了 Scott Meyers 的 std::weak_ptr 示例的要点?

Effective Modern C++(第 136 页)使用以下示例来激励std::weak_ptr. 缓存被定义为一个无序映射,其中指向对象的弱指针作为值。每当这个缓存的客户端请求一个对象(按键)时,相应的弱指针就会被查找并lock()在其上调用。如果结果std::shared_ptr不是null,则返回。否则,对象将从外部数据库重新加载,输入缓存并std::shared_ptr返回给它。

现在的问题是:有人可能认为可以在没有 的情况下实现这一点std::weak_ptr,而是将强共享指针存储为缓存值。如果use_count()一个强指针的值等于1,那意味着所有客户端的指针都被销毁了。这个例子的重点是使用std::weak_ptr允许我们通过实际删除对象来节省内存吗?

0 投票
1 回答
366 浏览

c++ - 在正确实现 Scott Meyer 的更有效的 C++ 第 22 条:“考虑使用 op= 而不是独立的 op”时避免通用引用?

我正在尝试遵循 Scott Meyers 在更有效 C++ 的第 22 项中的建议:“考虑使用op=而不是独立op”。他建议我们可以创建一个模板operator+,这样所有实现的类都会operator+=自动获得operator+

现在,在 Effective Modern C++ 的第 25 项中,有一个矩阵加法的示例(第 172 页),其中operator+建议使用右值重载,因为如果您知道lhs或者rhs是右值,您可以使用它们来存储结果,防止可能是巨大矩阵的无用副本。所以我添加了重载:

这里的问题是它T&&是一个通用引用,它最终会捕获所有内容,所以我最终从左值移动,这是不受欢迎的行为。

那么如何正确实现operator+模板呢?

使用按值传递的部分解决方案:我还阅读了来自 Effective Modern C++ 的第 41 条:“考虑通过值传递可复制参数 ...”,因此我尝试编写自己的版本,如下所示:

但这错过了当 rhs 是右值时的优化机会,因为在这种情况下,我不会使用 rhs 来存储结果。所以这只是部分解决方案。

0 投票
2 回答
833 浏览

c++ - 自动类型扣除中的 const

我正在阅读 Scott Meyers 的《Effective modern C++》。第 1 项包含以下示例:

在第 3 项中出现以下示例:

根据第 1 项,我期望myWidget1的类型是const Widget。我错过了什么吗?

0 投票
2 回答
265 浏览

c++ - 有效的 C++ 项目 11 处理对自身的赋值

我正在阅读这本书,但我不明白两段代码之间的区别。

迈耶斯先生说:

如果“new Bitmap”表达式产生异常,Widget 将最终持有指向已删除 Bitmap 的指针。

这是否意味着pd指针指向 NULL?

迈耶斯先生说:

现在,如果“new Bitmap”抛出异常,pb 指针保持不变。

据我所知,temp指针指向与pb指针相同的内存地址。如果 "new" 抛出异常,pb将指向 NULL,下一句将删除 Bitmap。那是对的吗?我看不出这些实现之间的区别。

提前致谢。

0 投票
1 回答
304 浏览

c++ - 尾随返回类型和右值

我正在阅读 Scott Meyers 的Effective Modern C++,我正在我的机器上尝试他为推导类型一章提供的示例。

他提供了这个功能:

然后它以这种方式使用该功能:

说它不会编译。我尝试使用 MSVC,它确实可以编译。我在中写了以下内容main

我不明白它为什么会编译,最重要的是,它显示10为双端队列的第一个元素。因为他解释这个代码是错误的。为什么它在这里工作?我错过了什么?

0 投票
0 回答
430 浏览

c++ - GCC -Weffc++ 运算符重载返回 `*this` 和 CRTP

Scott Meyers 的Effective C++建议赋值运算符应返回对*this. GCC-Weffc++似乎概括了这一原则,建议就地算术运算符(例如 prefix ++)的重载也应该返回对类类型实例的引用。

但是对于CRTP,GCC 显然无法识别然后返回正确的引用类型:

这里,DERIVED&是真正应该返回的类型,因为它Bar不是. 但 GCC 给出以下警告:Foo<Bar>Bar

第一个警告有点明智——编译器无法判断该类旨在用于 CRTP,因此它没有意识到该类DERIVED将继承自Foo<DERIVED>. (编辑:实际上,通过使用 astatic_cast而不是 C 风格的转换,您确实可以确保它DERIVED确实是派生类型,因此如果编译器推迟发出此警告,直到查看函数的实现,它甚至可以抑制误报没有看到Bar.) 的定义。但是第二个警告,它看到了实际的 CRTP 声明,对我来说根本没有意义,因为它应该能够告诉它Bar&算作Foo<Bar>&.

但是,当使用带有运算符重载的 CRTP 时,即使是第一个警告也是虚假的。这是否意味着-Weffc++根本不能与 CRTP 一起使用(假设您想避免虚假警告)?

0 投票
1 回答
319 浏览

c++ - 通用类型演绎斯科特迈耶斯

我正在阅读 Scott Meyers 的《Effective modern C++》

对于作为函数参数的通用引用,初始化程序在调用站点提供。

为了使引用具有普遍性,类型推导是必要的,但这还不够。引用声明的形式也必须正确,而且 from 是相当受限制的。它必须是精确的“ T&&”。

当 f 被调用时,类型T将被推断出来(除非调用者明确指定它,这是我们不会关心的边缘情况)。但是param的类型声明的形式不是“ T&&”,而是“ std::vector<T>&&”。这排除了 param 是通用参考的可能性。因此 param 是一个右值引用,如果您尝试将左值传递给f

在上面我有以下问题

  1. 作者所说的“除非调用者明确指定它,否则我们不会关心的边缘情况”是什么意思?请求提供示例什么是边缘案例作者提到调用者明确指定
0 投票
4 回答
956 浏览

c++ - 在 C++ 中检测事件的条件变量用法 scott meyers

我正在阅读 Scott Meyers 所著的 Effective Modern C++ 中的条件变量,下面是文本。

这里作者提到如下

互斥体用于控制对共享数据的访问,但检测和反应任务完全有可能不需要这种中介。例如,检测任务可能负责初始化一个全局数据结构,然后将其交给反应任务使用。如果检测任务在初始化后从未访问过数据结构,并且如果反应任务在检测任务指示它已准备好之前从未访问过它,则这两个任务将通过程序逻辑相互避开。不需要互斥锁。

在上面的文字我很难理解

  1. 作者所说的“两个任务将通过程序逻辑相互隔离”是什么意思?

  2. 作者不需要互斥锁是什么意思?

0 投票
3 回答
1314 浏览

c++ - 为什么在 Effective C++ 中以这种方式定义声明和定义?

Effective C++(第 3 版)第 2 项(Preferconst和to )中enum,类特定常量的代码段如下:inline#define

然后这本书说(用我自己的话)这static const int NumTurns = 5;不是一个定义,这通常是 C++ 对类成员所要求的,除非它是一个地址从未使用过的静态整数常量。如果以上对于常量不成立,或者编译器出于任何原因坚持定义,则应在实现文件中提供定义,如下所示:

根据这本书(也是我自己的话),定义中没有给出任何值,因为它已经在声明中给出了。

这让我认为我已经知道声明和定义的定义令人困惑(在问这个问题之前我在谷歌上仔细检查过):

  • 为什么static const int NumTurns = 5没有定义?不是在这里NumTurns初始化为一个值5,是不是声明和定义一起出现的时候才叫初始化?
  • 为什么static整数常量不需要定义?
  • 当没有定义值时,为什么第二个代码片段被认为是定义,但包含该值的类内部的声明仍然不是一个(基本上回到我的第一个问题)?
  • 初始化不是定义吗?为什么这里没有违反“唯一一个定义”的规则?

可能我现在只是在这里混淆了自己,所以有人可以从头开始重新教育我:为什么这两行代码声明和定义而不是另一行,那里有任何初始化实例?初始化也是一个定义吗?

信用:代码片段直接从书中引用。

编辑:附加参考定义和声明之间有什么区别?

  • 声明引入了标识符和类型
  • 定义实例化和实现

所以,是的......这似乎不是这里发生的事情。

编辑 2:我认为编译器可能会优化静态整数常量,方法是不将其存储在内存中,而只是在代码中内联替换它。但是如果NumTurns使用地址,为什么声明没有自动变为声明+定义,因为实例化已经存在?

编辑3:(此编辑与原始问题的关系不大,但仍然很突出。我把它放在这里,这样我就不需要复制粘贴到下面每个答案的评论中。请回答我这个在评论中。谢谢!)

感谢您的回答。现在我的头脑更清晰了,但编辑 2 的最后一个问题仍然存在:如果编译器在程序中检测到需要定义的条件(例如&NumTurns,在程序中使用),为什么它不自动重新解释static const int NumTurns = 5;为声明和定义而不是仅声明?它具有程序中其他任何地方的定义所具有的所有语法。

我来自学校的Java背景,并且不需要以上述方式为静态成员进行单独的定义。我知道 C++ 是不同的,但我想知道为什么上面是这样的。如果地址从不使用,则静态整数成员被内联替换,这对我来说更像是一种优化而不是基本功能,所以为什么我需要解决它(在条件不存在时提供单独的语句作为定义即使原始语句的语法足够了)而不是相反(编译器将原始语句视为定义,因为语法足够,所以需要有一个定义)?