前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++0x 通用属性

C++0x 通用属性

作者头像
恋喵大鲤鱼
发布2018-09-27 16:03:26
8700
发布2018-09-27 16:03:26
举报
文章被收录于专栏:C/C++基础C/C++基础

1.编译器扩展属性

C++在不断的发展,但每一阶段的C++标准提供的功能都很难完全满足现实需求,于是为了弥补标准的不足或者扩增特性应用场景所需的特性,各大C++编译器厂商多多少少在标准之外都增加了不少有用的扩展功能。这些扩展功能并不在C++的标准中,但是却经常被使用。有时候,C++标准委员会也会考虑这些标准之外的扩增特性,将其纳入标准之中。

C++扩增特性中较为常见的就是“属性”(attribute)。属性是对语言中实体对象(比如函数、变量、类型等)附加说明,用来语言及非语言层面的功能,或是帮助编译器优化代码。不同编译器有不同的属性语法,比如对于GNU ,属性是通过关键字__attribute__来声明的,常见的有format、noreturn、const和aligned等,申明语法如下:

代码语言:javascript
复制
__attribute__ ((attribute-list))

例如:

代码语言:javascript
复制
extern int area(int n) __attribute__ ((const))

int main()
{
    int areas=0;
    for(int i=0;i<10;++i)
    {
        areas+=area(3)+i;
    }
}

程序中const属性告诉编译器,该函数返回值只依赖于输入,不会改变函数外的数据,因此编译器可以对area(3)进行优化处理,只对函数调用一次,后续将area(3)视为常量进行操作,将大大提醒程序性能。

Windows平台VC++则使用__declspec来申明扩展属性,使用语法如下:

代码语言:javascript
复制
__declspec (extended-decl-modifier)

比如控制类型对齐方式:

代码语言:javascript
复制
__declspec (align(32)) struct Struct32
{
    char c;
    int i;
} 

其作用是类型Struct32定义的变量的其实地址是32的整数倍,且类型大小sizeof(Struct32)=32也是32的整数倍。

2.C++11通用属性

2.1语法格式

自C++11开始,C++拥有统一形式的通用属性申明方式,语法格式如下:

代码语言:javascript
复制
[[attribute-list]]

语法上,C++11通用属性可以作用于函数、类型、变量、代码块等,书写位置可以位于目标之前,也可以位于目标之后。对于作用于整个语句的通用属性,则应该写在语句起始处。如果出现在以上两种位置之外的通用属性,作用于哪个实体跟编译器具体实现有关。例如:

代码语言:javascript
复制
//作用于函数
[[ attr1 ]] void func();
//或者
void func [[ attr2 ]] ();

//作用于数组
[[ attr1 ]] int array[10];
//或者
int array [[ attr1 ]] [10];

C++11只定义了两种通用属性,分别是[[ noreturn ]]与[[ carries_dependency ]],其它如[[ final ]]、[[ override ]]、[[ restrict ]]、[[ hides ]]、[[ base_check ]]等属性,考虑到通用性和实现方式,未纳入标准,比如final、override、restrict等为语言特性,通过关键字来实现。

2.2[[ noreturn ]]

[[ noreturn ]]用于标识不会返回的函数。不会返回的函数指的是被调处后面的代码不会执行,被调函数不会将控制流返回给主调函数,注意不是没有返回值的函数。通过这个属性,开发者可以告诉编译器进行代码优化,诸如死代码告警与消除等。参考如下示例:

代码语言:javascript
复制
void cout1() { cout << "cout1" << endl; }
void cout2() { cout << "cout2" << endl; }

[[noreturn]] void throwAway()
{
    throw "exception";
}

void foo()
{
    cout1();
    throwAway();
    cout2();        //该函数不可达
}

上面的代码中,cout2()不可达,编译器可以采用告警的方式提示开发者或者直接不生成调用cout2()的代码进行优化。

除了抛出异常可能会导致程序控制流不能返回调用者外,其它诸如包含终止应用程序或者无限循环语句的函数,都可以使用[[noreturn]]进行申明,比如C++11标准库中,我们可以看到如下函数申明语句:

代码语言:javascript
复制
[[noreturn]] void abort(void) noexcept;

当然,[[noreturn]]可以帮助编译器进行代码优化,前提是正确使用。如果错误地使用[[noreturn]]可能会给程序带来致命损害,因此要小心翼翼。

2.3[[carries_dependency]]

[[ carries_dependency ]]作用于函数参数与返回值,用于避免在弱一致性模型平台上产生不必要的内存栅栏,降低代码效率。比如:

代码语言:javascript
复制
atomic<int*> a;
...
int* p=(int*)a.reload(memory_order_consume);
func(p);

由于编译器在编译到func时不知道func中的具体实现,因为使用了原子变量a对p赋值时使用了memory_order_consume内存顺序模型,所以需要保证a.load先于任何关于a(或者p)的操作,编译其往往会在func函数之前加入一条内存栅栏。然而如果func的实现是:

代码语言:javascript
复制
void func(int* p)
{
    //...假设p2是一个atomic<int*>的变量
    p2.store(p,memory_order_release);
}

那么对于func函数来说,由于使用memory_order_release的内存顺序,p2.store对p的使用会被保证在任何关于p的操作之后进行。这样一来,编译器在func函数之前加入内存栅栏毫无意义,并影响了性能,解决办法是对函数参数使用[[ carries_dependency ]]属性:

代码语言:javascript
复制
void func(int* [[ carries_dependency ]] p);

同样的,[[ carries_dependency ]]也可以用于返回值,语法格式如下:

代码语言:javascript
复制
[[ carries_dependency ]] int* func();

事实上,对于强内存模型平台来说,如x86-64,编译器往往会忽略该属性,因此该属性使用比较有限。如果开发平台是弱类型模型,并且很关心并行程序的执行性能时,可以考虑使用[[ carries_dependency ]]。

3.C++14与C++17通用属性

在C++11的基础上,C++新标准C++14与C++17对通用属性进行了补充,主要有:

(1)[[deprecated]]与[[deprecated(“reason”)]] 标准:C++14; 作用:指示允许使用声明有此属性的名称或实体,但因reason不鼓励使用; 示例:class [[deprecated]] Outdate{};

(2)[[fallthrough]] 标准:C++17; 作用:出现在switch语句中,抑制上一句case没有break而引起的fallthrough的警告; 示例:

代码语言:javascript
复制
switch(i) 
{
    case 1: something();[[fallthrough]];
case 2:something();[[fallthrough]];
default:break;
}

(3)[[nodiscard]] 标准:C++17; 作用:若返回值被舍弃,则鼓励编译器发出警告。 示例:

代码语言:javascript
复制
[[nodiscard]] int something()
{
    return 1;
}

(4)[[maybe_unused]] 标准:C++17; 作用:抑制编译器在未使用实体上发出警告。 示例:

代码语言:javascript
复制
 [[maybe_unused]] int a = something();

使用以上通用属性,可以帮助我们更好的优化和管理代码。C++20已经在路上,新标准会继续在通用属性方面作出更多的扩增。


参考文献

[1]深入理解C++11[M].8.2通用属性 [2]《深入理解C++11》笔记-对齐支持和通用属性 [3]attribute specifier sequence(since C++11) [4]C++的属性指示符

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018年08月27日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.编译器扩展属性
  • 2.C++11通用属性
    • 2.1语法格式
      • 2.2[[ noreturn ]]
        • 2.3[[carries_dependency]]
        • 3.C++14与C++17通用属性
        • 参考文献
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档