本节提供了在 Oracle Developer Studio 12.5 C++ 5.14 编译器发行版中引入的新增特性和已更改功能的摘要列表。
支持 SPARC M6、M7 和 T7 处理器。
支持 Intel Broadwell/avx2_i 处理器。
支持 x86 数据空间分析。
Oracle Solaris 上的缺省编译模式是使用 –library=Cstd 的 –compat=5(使用 Sun ABI 和 libCstd 库的 C++03 模式)。Oracle Linux 上的缺省编译模式是 –std=c++03(使用 g++ ABI 和运行时库的 C++03 模式)。
在所有平台上的 –compat=5 模式下,现在,缺省值是正确的名称改编。以前,名称改编中的错误是 SPARC 上的缺省值和使用 –m32 的 x86 上的缺省值。
新编译器选项:
–abiopt=[mangle5|mangle6] 仅在 –compat=5 模式下可用。缺省值是 mangle6,即正确的名称改编。在 Oracle Solaris SPARC 上以及使用 –m32 的 Oracle Solaris x86 上,可以指定 mangle5 以便与早期编译器中可能有错误的名称改编兼容。
–features=[no%]mergestrings 可使编译器将字符串文字以及其他合适的 const 或只读数据放入二进制文件的一个特殊部分中,链接程序将从中删除重复的字符串。此选项仅在 SPARC 上可用。
–pedantic 针对缺省情况下接受的但未遵循 C++ 标准的代码发出警告或错误。
–xatomic 指定链接哪个原子支持运行时库。
–xcheck=noreturn 通知编译器当已描述为“不返回”的例程返回时添加代码来导致运行时错误。
–xsecure_code_analysis 启用编译器安全代码分析,以便在编译时查找和显示可能的内存安全违规。
Oracle Developer Studio 12.5 提供对 C++11 的完全支持。
随 Oracle Solaris Studio 12.4 提供的 g++ 4.8.2 库未遵循 C++11 的所有要求。具体而言,标准字符串和列表类需要进行更改,这会破坏二进制兼容性。
g++ 5.1 发行版可以在与 g++ 4.x 兼容或遵循 C++ 标准之间选择。这些选择互不兼容。文章 GCC5 和 C++11 ABI 中提供了有关使用 g++ 的更详细信息。
–std=c++11 或 –std=c++14 模式下的 Oracle Developer Studio 12.5 提供了与 Oracle Solaris Studio 12.4 和 g++ 4.8.2 的兼容性。Oracle Developer Studio 12.5 未提供不兼容的遵循标准的选项。
如果要将 g++ 5.1 二进制文件与 Oracle Developer Studio 二进制文件组合在一起,必须在每个 g++ 命令行上使用 –D_GLIBCXX_USE_CXX11_ABI=0 选项编译所有 g++ 二进制文件。
Oracle Developer Studio 12.5 提供对 C++14 标准的有限支持。支持以下功能:
二进制文字
固定大小的取消分配
deprecated 属性
单引号数字分隔符
成员初始化和聚集
原子是 C++ 2011 标准中新增的一种语言功能。原子功能仅对 –std=c++11 和 –std=c++14 选项可用。有关支持的函数和类型的信息,请参见 C++ 语言标准以及 atomic_fence(3A)、atomic_flag(3A) 和 stdatomic.h(3A) 手册页。
原子功能需要运行时支持。有关运行时库的更多信息,请参见捆绑的原子库。
Oracle Developer Studio 12.5 C++ 5.14 编译器比过去的编译器更严格地强制执行某些 C++ 规则。规则实施错误导致早期的编译器无法正确处理某些有效代码。本节说明更严格的实施,提供错误代码的示例,并显示如何修复代码。在所有这些例子中,您都可以更改代码,随后该代码应在新旧编译器中正常运行。
以前的编译器不解析模板定义,直到实例化模板后才会进行解析,这会产生以下后果:
以前的编译器直到定义模板后才允许使用未声明的名称。这可能会因明显的冲突而导致无效代码被接受,有效代码被拒绝,或使用错误的声明。
无法诊断出未实例化的模板中的无条件错误。
只有在实例化模板 T 后,才会实例化模板 T 的定义中不依赖于模板参数的名称。这些名称应在定义 T 时隐式实例化。
示例 1:
template< class T > int f(int i = j) // j is not visible { return i; } int j = 2; int main() { return f<int>(); }
早期的编译器接受此代码,因为只有在定义了 j 后才会解析模板 f。
解决方法:在定义模板之前声明 j。
示例 2:
#include <stdio.h> void f(double d) { printf("f(double)\n"); } template< class C > struct B { B() { f(1); } // f is not dependent on template parameter }; void f(int d) { printf("f(int)\n"); } int main() { B<int> b; // should print "f(double)" }
解决方法:确保在定义模板之前进行模板所依赖的任何声明。
在模板定义中查找未限定的名称时,不应检查依赖于模板参数的基类。以前的编译器对名称的查找不正确。
示例:
template <typename T> struct Base { }; template <typename T> struct Derived : Base <T> { Derived() : Base() { } // unqualified Base should not be found }; Derived <int> x; template <typename T> struct Derived2 : Base <T> { Derived2() : Base<T>() { } // OK }; Derived2<int> x2; int main() { }
在类 Derived 中,使用未限定的 Base 而没有模板参数是无效的。
解决方法:在类 Derived2 中,这种用法是正确的。
您不能再重新声明模板参数的名称。
示例:
template <typename T> class A { typedef int T; }; // re-declare T
解决方法:为模板参数或本地名称选择其他名称。
不再支持前向模板声明。
示例:
$ cat x.cc template <> struct A<int>; . $ CC x.cc "x.cc", line 1: Error: A class template name was expected instead of A<int>.
Oracle Developer Studio C++ 的以前发行版会无提示地将此接受为由具有一个类型参数的名称 "A" 对隐式声明的模板的显式专门化。
解决方法:在任何显式专门化之前声明主要模板。
template<class T> struct A; template <> struct A<int>;
不再允许使用 1998 之前的不带 template<> 的显式专门化声明样式。
示例:
template <typename T> class A { static T m; }; int A<int>::m = 0; // now an error
解决方法:
template<> int A<int>::m = 0;
请参阅独立的模板定义。“独立模板定义”编译模型现在更严格了。如果要创建的 X.cc 文件包含在头文件 X.h 中声明的模板的定义,必须特别小心,不要在该文件中添加其他任何内容(即,除了与定义直接相关的项目之外的任何内容)。现在如果违反了此规则,则可能得到“多个定义”错误。
示例:
% cat extdef.h template <typename T> T foo(T); % cat extdef.cc #include "extdef.h" int main() { foo(1); } % CC extdef.cc -template=extdef "extdef.cc", line 3: Error: main() already had a body defined. 1 Error(s) detected.
解决方法:从 X.cc 文件中删除模板定义不需要的任何内容。请记得 X.cc 文件无需显式编译,因为只要包括 X.h 文件,就会自动包括它。
如果需要进行其他更改,可考虑使用 -template=no%extdef 选项进行编译。此行为是其他编译器的缺省行为,现在也是此发行版的缺省行为。
在 C++ 中从不允许隐式声明类型 int,但早期的编译器有时允许声明并显示警告。由于这干扰了正常的模板处理过程,因此编译器不再假定您要声明类型 int。
示例:
static i = 0; // now an error
解决方法:在声明中显式提供类型。
如果类 C 中函数的友元声明或类 T 是 T 的第一个声明,以前的编译器会错误地将 T 的声明插入周围作用域。Oracle Developer Studio 12.5 C++ 5.14 编译器不再这样做,因为它可能会导致对有效程序的错误解释。
示例:
class A { friend class B; // not previously declared friend void foo(); // not previously declared B* bar() // Error: B is not defined. { foo(); // Error: The function "foo" must have a prototype. return 0; } };
解决方法:在将类声明为友元的类声明之前,在该类之外的作用域中声明友元函数或类。
class B; void foo(); class A { friend class B; // refers to prior declaration friend void foo(); // refers to prior declaration B* bar() // OK { foo(); // OK return 0; } };
指定了缺省参数的友元声明还必须是函数定义。
示例:
class C { friend int f1(int i = 0); // Error friend int f2(int i = 0) { return i; } // OK }
C++ 编译器的以前发行版不强制执行此规则。允许在友元声明中使用缺省参数会干扰正常的模板处理,因此不再允许这样做。
在相关函数调用中查找名称时,以前的编译器会错误地忽略作用域中的静态函数。Oracle Developer Studio 12.5 C++ 5.14 编译器现在以相同方式处理 static 和 extern 函数。
示例:
// previous compiliers ignored this bar() in dependent name lookup static int bar(int) { return 1; } int bar(long) { return 0; } template <typename T> int foo(T t) { // function call depends on template argument return bar(t); } int main() { return foo(0); }
使用以前的编译器编译时,程序会返回 0。使用 Oracle Developer Studio 12.5 C++ 5.14 编译器时,程序会返回 1。
如果在名称查找中只找到静态函数,以前的编译器会发出类似如下的错误
"Reference to static bar(int) not allowed in template foo(int), try using -features=tmplrefstatic."
请参见前面的示例,删除 extern 函数 bar(long)。编译器现在只在 -compat=5 模式下发出警告,因为该代码在技术上是对 C++03 标准的扩展。在 C++11 模式中,将接受此代码而不显示任何提示,因为它是有效的 C++11。
仍接受选项 -features=no%tmplrefstatic,但它没有实际作用,因为始终允许对模板中的静态对象的引用。
以前的编译器不强制执行可保留关键字 const 的属性的所有规则。
示例:
void f1(int**) { printf("f1(int**)\n"); } void f2(int**) { printf("Error: f2(int**)\n"); } void f2(...) { printf("OK: f1(...)\n"); } int main() { int* const p = 0; f1(&p); // #1 Should be an error f2(&p); // #2 Should choose f2(...) }
早期的编译器错误地接受了 #1,而对于 #2,则错误地调用了 f2(int**)。如第 2 行所示,由于编译器的错误行为所致,可能会选择错误的重载函数或错误的模板专门化。
可以修复第 1 行,方法是声明
int* p = 0;
或者更改 f1 的定义或添加重载
void f1(int * const*);
如果您希望现有的无效代码继续编译,则可以将未编档的选项
-W0,-xconstcheck=false [note: W-zero, not W-oh]
添加到 CC 命令行,该命令行现在生成有关 const 正确性的警告消息。