前瞻性声明的危险是什么?

Off*_*rmo 24 c++ forward-declaration

我刚接受采访.我被问到什么是"前瞻性声明".然后我被问到他们是否是与前瞻性声明有关的危险.

我无法回答第二个问题.在网上搜索没有显示任何有趣的结果.

那么,有人知道与使用前向声明有关的任何危险吗?

Mat*_* M. 15

好吧,除了有关复制的问题......

......标准中至少有一个疼痛部位.

如果调用delete指向不完整类型的指针,则会得到未定义的行为.实际上,析构函数可能不会被调用.

我们可以使用以下命令和示例在LiveWorkSpace上看到:

// -std=c++11 -Wall -W -pedantic -O2

#include <iostream>

struct ForwardDeclared;

void throw_away(ForwardDeclared* fd) {
   delete fd;
}

struct ForwardDeclared {
   ~ForwardDeclared() {
      std::cout << "Hello, World!\n";
   }
};

int main() {
   ForwardDeclared* fd = new ForwardDeclared();
   throw_away(fd);
}
Run Code Online (Sandbox Code Playgroud)

诊断:

Compilation finished with warnings:
 source.cpp: In function 'void throw_away(ForwardDeclared*)':
 source.cpp:6:11: warning: possible problem detected in invocation of delete operator: [enabled by default]
 source.cpp:5:6: warning: 'fd' has incomplete type [enabled by default] 
 source.cpp:3:8: warning: forward declaration of 'struct ForwardDeclared' [enabled by default]
 source.cpp:6:11: note: neither the destructor nor the class-specific operator delete will be called, even if they are declared when the class is defined
Run Code Online (Sandbox Code Playgroud)

你不想感谢你的编译器警告你;)?


Luc*_*ore 7

我会说任何危险都会被收益黯然失色.但有一些,主要与重构有关.

  • 重命名类会影响所有前向声明.这当然也包括,但错误是在不同的地方产生的,因此更难以发现.
  • 将类从a移动namespace到另一个,再加上using指令,可能会造成严重破坏(神秘错误,难以发现和修复) - 当然,using指令很难开始,但没有代码是完美的,对吧?*
  • 模板 - 转发声明模板(尤其是用户定义的模板),您需要签名,这会导致代码重复.

考虑

template<class X = int> class Y;
int main()
{
    Y<> * y;
}

//actual definition of the template
class Z
{  
};
template<class X = Z> //vers 1.1, changed the default from int to Z
class Y
{};
Run Code Online (Sandbox Code Playgroud)

Z之后类被更改为默认模板参数,但原始前向声明仍然是int.

*我最近碰到了这个:

原版的:

定义:

//3rd party code
namespace A  
{
   struct X {};
}
Run Code Online (Sandbox Code Playgroud)

和前瞻性声明:

//my code
namespace A { struct X; }
Run Code Online (Sandbox Code Playgroud)

重构后:

//3rd party code
namespace B
{
   struct X {};
}
namespace A
{
   using ::B::X;
}
Run Code Online (Sandbox Code Playgroud)

这显然使我的代码无效,但错误不是在实际的地方,并且修复至少可以说是腥.

  • "肆虐",而非"破坏危险" (4认同)
  • 打开第三方命名空间并为*他们的*类添加前向声明不是我在采访中提到的. (2认同)

Gam*_*per 7

前向声明是C++ 缺少模块(将在 C++17 中修复?)和使用头文件包含的症状,如果 C++ 有模块,则根本不需要前向声明。

前向声明不低于“合同”,通过使用它,您实际上承诺您将提供某些东西的实现(在同一源文件中之后,或稍后通过链接二进制文件)。

这样做的缺点是您实际上必须遵守合同,这不是什么大问题,因为如果您不遵守合同,编译器会以某种方式提早抱怨,但在某些语言中,代码只需执行而无需“承诺其”自己的存在”(说到动态类型语言)