【问题标题】:Compiler warning when creating custom std stream implementation创建自定义标准流实现时的编译器警告
【发布时间】:2011-08-03 19:37:04
【问题描述】:

我有一个 Visual Studio 2008 C++ 应用程序,我在其中创建了一个自定义 streambuf 和流实现。我使用了Angelika Langer 给出的方法来创建下面详述的流:

class MyOutputStream_3 : private MyStreamBuf, public ostream {
public:
    MyOutputStream_3() : ostream((MyStreamBuf*) this), ios(0) {};
    virtual ~MyOutputStream_3() { sync(); }
    // ...
}; 

但是,Visual Studio 给了我一个warning

warning C4355: 'this' : used in base member initializer list

代码运行良好,但我担心编译器会告诉我我所做的工作在某些情况下可能会中断,或者可能是不可移植的。

在这种情况下我可以忽略这一点吗?或者我应该怎么做才能解决我的问题?

【问题讨论】:

  • 从不忽略警告。
  • @Tomalak - 你是说给出的代码不正确,我应该改变它吗?如果是这样,怎么做?或者,您是说我应该记住这个警告,因为未来的更改很容易使代码不正确?
  • 到目前为止,我还无法确定代码可能不正确/未定义的原因。这并不意味着它不是,而且您的编译器比我更了解该语言。也可能有一个“小心;你的代码很容易因为最轻微的变化而出现严重错误!”因素,这也是不忽略警告的充分理由。它们不只是为了好玩而发出的! [我并不是说您必须更改您的代码;也不要完全忽略警告。某处有一个中间地带。 :)]

标签: c++ stream compiler-warnings


【解决方案1】:

警告您在初始化列表中使用this,因为从技术上讲,this 尚不存在,因为构造函数尚未完成执行(也没有任何成员对象的构造函数)并传递它当他们尝试使用该对象(其中包含尚未调用其构造函数的对象)时,函数可能会导致问题。

如果您只是存储指针以供以后使用,该代码应该可以工作。但是,当您回到这段代码并忘记您不应该使用该指针时,您可能会犯错误并且无法解释程序崩溃的原因。

这是该警告的 Microsoft 页面:http://msdn.microsoft.com/en-us/library/3c594ae3.aspx

【讨论】:

    【解决方案2】:

    C++03 标准在 12.6.2/7“初始化基数和成员”的注释中有这一点:

    [注意:因为 mem-initializer 是在构造函数的范围内计算的,所以 this 指针可以用在 mem-initializer 的表达式列表中来引用正在初始化的对象。 ]

    我认为发出警告是因为this 指针所引用的对象未完全初始化,因此存在一些潜在危险。只要在初始化之前您的基础实际上没有使用对象的未初始化部分,那么您应该没问题。

    作为警告 (http://msdn.microsoft.com/en-us/library/3c594ae3.aspx) 的 MSDN 文档提到:

    实际上,您已将指向未构造对象的指针传递给另一个构造函数。如果那些其他构造函数访问任何成员或在 this 上调用成员函数,则结果将是未定义的。

    【讨论】:

    • 我确信我读过一次,在派生实例完全构造之前将this 转换为基本类型是UB。
    • 顺便说一下,[2003: 9.3.2] 似乎并没有在成员初始化器中实际定义 this 的类型。
    • @Tomalak:给定struct D : B { D() : B(this) { } };,出现在初始化列表中的thisD* 类型。在 C++03 §12.7/2 中有一个这样的例子,尽管这种行为也被分派虚函数的方式所暗示。 (我承认我不知道指定这一点的规范性文本在哪里。)
    • @Michael - 所以,如果我理解你的话,只要std::ostream 不依赖MyOutputStream 尚未构建的部分,我应该没问题。在这种情况下,它只依赖MyStreamBuf,因为它是继承列表中的第一个,所以首先构造它。那么,上面的代码应该是正确的吧?
    • @James:我认为 2003 年没有 任何规范性定义。我们可能可以依赖示例和常识,但是..
    【解决方案3】:

    顺便说一句,这只发生在您在 mem-initializer 列表中明确使用 this 时。传递尚未构造的成员变量的地址不会引发 C4355。

    如果需要证明,请查看fstream 的构造函数。

    【讨论】:

      猜你喜欢
      • 2014-04-12
      • 1970-01-01
      • 2017-09-27
      • 2010-11-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多