3

就在我以为我了解 C++11 中 iostream 的多遍移动构造时(感谢https://stackoverflow.com/a/8156356/273767的介绍),我遇到了这个问题:

§27.7.2.5.1[iostream.cons]/3

basic_iostream(basic_iostream&& rhs);

3basic_istream效果:通过使用 构造基类,从右值 rhs 移动构造move(rhs)

那么另一个基地会发生什么basic_ostream

我看到 libc++ 提供了std::basic_ostream一个受保护的默认构造函数,它在此处被调用(并且与 §27.7.2.5.1/1 的字母相矛盾,在basic_iostream 的普通构造函数中),并且什么也不做。这就是它应该的样子吗?

4

2 回答 2

7

正如您所指出的,规格:

explicit basic_iostream(basic_streambuf<charT,traits>* sb);

初始化两个基。我从来没有接受过:

http://cplusplus.github.com/LWG/lwg-closed.html#135

因为它会导致单个 basic_ios::init()函数在同一个虚拟基础对象上被调用两次。委员会裁定这种双重初始化是无害的。我非常不同意,以至于我拒绝实施关于这个细节的规范。但是规范说要双重初始化虚拟基类。

当需要指定basic_iostream移动构造函数时,我坐在驾驶座上。所以我指定了我认为最好的方式(不要双重初始化basic_ios)。该决定尚未受到挑战,但最终可能会受到挑战。

请注意,为了避免双重初始化,basic_ostream必须仔细设计默认构造函数以完全不做任何事情。我什么都不是。无零初始化:

protected:
    _LIBCPP_ALWAYS_INLINE
    basic_ostream() {}  // extension, intentially does not initialize

幸运的是, 的基类basic_ostream实际上在其默认构造函数中被指定为不做任何事情。所以一切正常: basic_ostream默认构造并且不触及内存。然后派生的客户只调用init(basic_streambuf<char_type, traits_type>*) 一次来执行basic_ios/的实际构造ios_base

这是一个非常混乱的设计。通过拒绝双重初始化虚拟基础,我觉得 libc++ 使设计不那么混乱,并且更可靠。这是移动构造函数的标准行为,而不是采用streambuf*.

于 2012-07-03T15:47:58.517 回答
3

我同意霍华德的观点,这是标准规范上的一种缺陷。

在我的实现中,我选择对构造函数扩展使用更具体的调用

basic_iostream(basic_iostream&& _Other)
   : std::basic_istream<char_type, traits_type>(std::move(_Other)),
     std::basic_ostream<char_type, traits_type>(basic_ostream::_NoInit)
{ }

protected在基类中使用特殊的构造函数

protected:    
    // special interface for basic_iostream

    enum __no_init_t { _NoInit };

    basic_ostream(__no_init_t)
    { }

净效果是一样的。

于 2012-07-03T16:26:27.330 回答