标签: gotw

C++最令人烦恼的解析

直接来自http://herbsutter.com/2013/05/09/gotw-1-solution/

虽然widget w();对我来说很清楚,但我不知道下面的代码如何成为函数声明?

// same problem (gadget and doodad are types)
//
widget w( gadget(), doodad() );  // pitfall: not a variable declaration
Run Code Online (Sandbox Code Playgroud)

这怎么可能?

c++ c++11 gotw

39
推荐指数
1
解决办法
4529
查看次数

最终课程的用例

我读的意见终极版约在一周的香草萨特的大师virtual功能,终于看见他提这一点:

[...]"最终的使用是罕见的" - 嗯,他们有点.我不知道很多,在标准化过程中,Bjarne反复询问它解决的问题和应该使用的模式的例子,我不记得任何突出的主要问题.我唯一知道的是,如果你正在定义一个库模块(它还不是标准概念),那么使叶子类最终可以为编译器提供更多信息来虚拟化调用,因为知道库外的代码"进一步推导出来,但我不确定这些日子在整个计划优化(包括积极的虚拟化)的存在下有多重要.

这个答案没有提供很多final关于课程用例的例子,我很想知道它可以解决哪些问题.你知道吗,或者final课堂上只会变成一些模糊不清且几乎未使用过的功能?

c++ inheritance c++11 gotw

22
推荐指数
1
解决办法
1319
查看次数

对于向量,为什么更喜欢迭代器而不是指针?

在Herb Sutter中When Is a Container Not a Container?,他展示了一个将指针放入容器的示例:

  // Example 1: Is this code valid? safe? good?
  //
  vector<char> v;

  // ...

  char* p = &v[0];

  // ... do something with *p ...
Run Code Online (Sandbox Code Playgroud)

然后跟着它"改进":

  // Example 1(b): An improvement
  //               (when it's possible)
  //
  vector<char> v;

  // ...

  vector<char>::iterator i = v.begin();

  // ... do something with *i ...
Run Code Online (Sandbox Code Playgroud)

但实际上并没有提供令人信服的论据:

一般来说,当你想指向一个容器内的对象时,更喜欢使用迭代器而不是指针并不是一个糟糕的指导.毕竟,迭代器在与指针大致相同的时间和相同的方式上无效,并且迭代器存在的一个原因是提供一种"指向"包含对象的方法.因此,如果您有选择,请更喜欢将迭代器用于容器中.

不幸的是,你不能总是得到与迭代器相同的效果,你可以使用指针到容器.迭代器方法有两个主要的潜在缺点,当适用时我们必须继续使用指针:

  1. 您不能总是方便地使用可以使用指针的迭代器.(见下面的例子.)

  2. 在迭代器是一个对象而不仅仅是一个光头指针的情况下,使用迭代器可能会产生额外的空间和性能开销.

在向量的情况下,迭代器只是一个RandomAccessIterator.对于所有意图和目的,这是指针上的薄包装.一种实现甚至承认这一点:

   // This iterator adapter is 'normal' in the sense that it does not …
Run Code Online (Sandbox Code Playgroud)

c++ pointers iterator vector gotw

22
推荐指数
3
解决办法
2435
查看次数

GotW#101"解决方案"实际上解决了什么问题吗?

首先阅读Herb's Sutters GotW关于C++ 11中pimpl的帖子:

我在理解GotW#101中提出的解决方案时遇到了一些麻烦.据我所知,在GotW#100中辛苦解决的所有问题都复仇了:

  • pimpl成员是外的线的模板,并且定义并不在使用点可见(在class widget的类定义和隐式生成的特殊成员函数widget).也没有任何明确的实例化.这将导致链接期间未解决的外部错误.

  • widget::impl实例化定义的点上仍然是不完整的(我认为它实际上根本没有pimpl<widget::impl>::~pimpl()实例化,只是被引用).因此std::unique_ptr<widget::impl>::~unique_ptr()调用delete指向不完整类型的指针,如果widget::impl有一个非平凡的析构函数,则会产生未定义的行为.

请解释是什么迫使编译器在widget::impl完成的上下文中生成特殊成员.因为我看不出它是如何工作的.


如果GotW#101仍然需要widget::~widget()在实现文件中明确定义,哪里widget::impl完成,那么请解释"更健壮"的评论(@sehe在他的答案中引用).

我看的GotW#101的核心要求是,包装"消除样板的一些作品",这在我看来(基于该段的其余部分)来表示的widget::~widget()声明和定义.所以请不要依赖于你的答案,在GotW#101中,那已经消失了!


Herb,如果你停下来,请告诉我是否可以在这里剪切+粘贴解决方案代码以供参考.

c++ pimpl-idiom incomplete-type c++11 gotw

21
推荐指数
2
解决办法
1856
查看次数

C++ 11类型演绎与const char*

GotW 94中,Herb Sutter区分了"经典C++"声明

const char* s = "Hello";
Run Code Online (Sandbox Code Playgroud)

和"现代"风格

auto s = "Hello";
Run Code Online (Sandbox Code Playgroud)

他告诉我们,有一个"中的类型细微的差别s,这里的auto风格是比较正确的." [编辑补充:评论表明,这可能不是Sutter实际意义的公平表示; 见下面的讨论.]

但是......有什么区别?我的印象是a const char *是引用字符串文字的正确方法.此外,当我问我的调试器(lldb)时,它似乎认为类型实际上是相同的:

* thread #1: tid = 0x1756c2, 0x0000000100000f8f test`main + 31 at test.cc:4, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x0000000100000f8f test`main + 31 at test.cc:4
   1    int main(void) {
   2        const char* s = "Hello";
   3        auto t = "Hello";
-> 4        return 0;
   5    }
(lldb) fr v
(const …
Run Code Online (Sandbox Code Playgroud)

c++ char auto c++11 gotw

10
推荐指数
2
解决办法
571
查看次数

对本周大师的理解#67:双重或无结果

最近,我正在阅读帖子:Herb Sutter对GOTW的双重或无效 我对以下程序的解释有点困惑:

 int main()
 {
     double x = 1e8;
     while( x > 0 )
     {
        --x;
     }
 }
Run Code Online (Sandbox Code Playgroud)

假设此代码在某台机器上运行1秒.我同意这样的代码是愚蠢的.

然而,每样,如果我们改变问题的解释xfloatdouble,那么在某些编译器,它会继续运行永远计算机.该解释基于该标准的以下引用.

引用C++标准的3.9.1/8节:

有三种浮点类型:float,double和long double.double类型提供至少与float一样多的精度,long double类型提供至少与double一样多的精度.float类型的值集是double类型的值集的子集; double类型的值集是long double类型的值集的子集.

代码的问题是:

如果你将"double"改为"float",你会期望它需要多长时间?为什么?

这是给出的解释:

它可能需要大约1秒(在特定实现上,浮点数可能稍微快一些,或者比双精度快一些,或者稍微慢一些),或者永远,这取决于浮点数是否可以精确地表示从0到1e8(包括0和1e8)的所有整数值.

标准的上述引用意味着可能存在可以用double表示但不能用float表示的值.特别是,在一些流行的平台和编译器中,double可以精确地表示[0,1e8]中的所有整数值,但float不能.

如果float不能准确表示0到1e8之间的所有整数值,该怎么办?然后修改后的程序将开始倒计时,但最终会达到无法表示的值N和N-1 == N(由于浮点精度不足)......

我的问题是:

如果float甚至不能表示1e8,那么当我们初始化时我们应该已经溢出float x = 1e8; 那怎么会让电脑永远运转呢?

我在这里尝试了一个简单的例子(虽然不是double但是int)

#include <iostream>

int main()
{
   int a = 4444444444444444444;
   std::cout << "a " << a << std::endl;
   return 0;
}
It outputs: a …
Run Code Online (Sandbox Code Playgroud)

c++ floating-point precision gotw

8
推荐指数
1
解决办法
287
查看次数

Gotw 67中的一个例子

http://www.gotw.ca/gotw/067.htm中有一个例子

int main()
{
  double x = 1e8;
  //float x = 1e8;
  while( x > 0 )
  {
    --x;
  }
}
Run Code Online (Sandbox Code Playgroud)

当你将double改为float时,它在VS2008中是一个无限循环.根据Gotw的解释:

如果float不能准确表示0到1e8之间的所有整数值,该怎么办?然后修改后的程序将开始倒计时,但最终将达到无法表示的值N和N-1 == N(由于浮点精度不足)......然后循环将保持卡住状态在该值上,直到运行程序的机器耗尽电量.

根据我的理解,IEEE754浮点数是单精度(32位),浮点数范围应为+/- 3.4e +/- 38,它应该有7位数字.

但我仍然不明白这究竟是怎么发生的:"最终达到一个无法表示的值N和N-1 == N(由于浮点精度不足)." 有人可以尝试解释这一点吗?

一些额外的信息:当我使用双x = 1e8时,它在大约1秒内完成,当我将其更改为浮动x = 1e8时,它运行的时间更长(5分钟后仍然运行),如果我将其更改为float x = 1e7;,它在大约1秒钟内完成.

我的测试环境是VS2008.

顺便说一句,我不是要求基本的IEEE 754格式解释,因为我已经明白了.

谢谢

c++ floating-point precision gotw

6
推荐指数
1
解决办法
495
查看次数

为什么要使用make_unique调用初始化unique_ptr?

取自:http://herbsutter.com/2013/05/22/gotw-5-solution-overriding-virtual-functions/

我们为什么要写:

auto pb = unique_ptr<base>{ make_unique<derived>() };
Run Code Online (Sandbox Code Playgroud)

而不仅仅是:

auto pb = make_unique<derived>();
Run Code Online (Sandbox Code Playgroud)

我唯一的猜测是,如果我们想要auto,我们需要帮助它推断出正确的类型(base这里).

如果是这样,那么对我来说,这将是真正值得怀疑的优点..键入auto然后在右侧输入很多初始化=..

我错过了什么?

c++ c++11 gotw c++14

6
推荐指数
2
解决办法
3847
查看次数

为什么不在GotW 54中调整大小并清除作品?

参考HerbSutter的文章Gotw 54,他解释说

  1. 正确的"收缩适合"矢量或deque和

  2. 完全清除矢量或双端队列的正确方法

我们可以使用container.resize()container.clear()执行上述任务,还是我错过了什么?

c++ vector deque gotw

3
推荐指数
1
解决办法
247
查看次数

什么"它不适用于作为对象成员的引用"在GotW#88中意味着什么?

草药萨特:

有效并发:使用锁定层次结构来避免死锁有效并发:打破Amdahl定律!»想要#88:候选人对于"最重要的常规"2008-01-01作者:Herb Sutter一位朋友最近问我下面的例子1是否合法,如果是的话是什么意思.它引发了一个很好的讨论,我想我会在这里发布.因为它已经接近GotW风格了,所以这些年后我还以为我会做另一个名誉......不,我没有做出新年决议来恢复写作常规的GotWs.:-)

JG问题Q1:以下代码是否合法C++?

// Example 1

string f() { return "abc"; }

void g() {
const string& s = f();
  cout << s << endl;    // can we still use the "temporary" object?
}
Run Code Online (Sandbox Code Playgroud)

A1:是的.这是一个C++特性......代码是有效的,并且完全符合它的样子.

通常,临时对象仅持续到它出现的完整表达式的结尾.但是,C++故意指定将临时对象绑定到堆栈上对const的引用会延长临时对象生命周期的生命周期,从而避免了常见的悬空引用错误.在上面的示例中,f()返回的临时值一直持续到结束大括号.(注意,这仅适用于基于堆栈的引用.它不适用于作为对象成员的引用.)

最初,我认为最后一句意思是:

class A 
{
public:
    int x;
    A(const int& x_)
    {
        x = x_;
    }
};

int main()
{
    A a(1); // assign lvalue to const int&
    std::cout << a.x;
}
Run Code Online (Sandbox Code Playgroud)

但是,它显然很好用.

那么,"它对于作为对象成员的引用不起作用"是什么意思?

c++ gotw

1
推荐指数
1
解决办法
61
查看次数