我什么时候使用“__attribute__((nonnull))”与 "not_null<T*>"?

When do I use "__attribute__((nonnull))" vs "not_null<T*>"?

我习惯于在表达不应为空的指针时使用__attribute__((nonnull))

void f(int* ptr) __attribute__((nonnull));

int main(){
    int* ptr = new int(1);
    f(ptr);
}
void f(int* ptr){/*impl*/}

但是,对于 GSL,还有 not_null<T*> 包装器类型。
void function1(gsl::not_null n);

void f(gsl::not_null<int*> n);

int main(){
    int* ptr = new int(1);
    f(ptr);
}
void f(gsl::not_null<int*> n){/*impl*/}

假设语言设施支持 GSL 版本,我现在应该始终使用 not_null<T*> 代替 __attribute__((nonnull)) 吗?

我的印象是编译器属性可能有助于优化,但包装器版本解析为未属性指针。

"should I always be using not_null in place of attribute((nonnull)) now?

not_null 似乎是更好的方法,原因如下:

__attribute__((nonnull)) seems to be gcc specific so this means that only gcc could use this attribute for optimizations, safety, security, static code analyzers (etc, you name it). This makes it not a very good choice if you want to use multiple compilers. Microsoft has for example __assume 可用于实现类似的结果。

gsl::not_null 不是标准模板库的一部分,因此不能保证它能以相同的方式在所有编译器上工作。您可能会发现在某些编译器上它不会做任何特别的事情。然而,这是一个更好的选择,因为 not_null 可以包装所有编译器变体以获得相同的结果(也可以添加运行时检查)。但从当前的实现来看(参见 link),仅支持使用 __assume 的 Microsoft 编译器(无法找到 gcc 的实现,但如果你有,那么使用它是一个优势)