Mik*_*ail 49 c++ pointers cpp-core-guidelines guideline-support-library
最近提出了C++核心指南(恭喜!),我担心gsl::not_null类型.如I.12中所述:声明一个不能为null的指针not_null:
帮助避免解除引用nullptr错误.通过避免对nullptr进行冗余检查来提高性能.
...
通过声明源代码中的意图,实现者和工具可以提供更好的诊断,例如通过静态分析查找某些类错误,并执行优化,例如删除分支和空测试.
目的很明确.但是,我们已经有了语言功能.不能为null的指针称为引用.虽然引用一旦创建就无法反弹,但这个问题可以解决std::reference_wrapper.
我gsl::not_null和之间的主要区别在于,std::reference_wrapper后者只能用于代替指针,而前者适用于任何事物 - 可nullptr分配(引自 F.17:使用not_null来表示"null"不是有效值):
not_null不只是内置指针.它的工作原理为array_view,string_view,unique_ptr,shared_ptr,和其他类似指针的类型.
我想象功能比较表如下:
T&:
nullptr?- 是的std::reference_wrapper<T>:
nullptr?- 是的gsl::not_null<T*>:
nullptr?- 是的现在这里是问题,最后:
std::reference_wrapper现在没用了?PS我创建了标签cpp-core-guidelines,guideline-support-library为此,我希望正确.
Jos*_*son 31
引用不是不能为null的指针.引用在语义上与指针非常不同.
引用具有值赋值和比较语义; 也就是说,涉及引用的赋值或比较操作读取和写入引用的值.指针具有(违反直觉的)引用赋值和比较语义; 也就是说,涉及指针的赋值或比较操作读取和写入引用本身(即引用对象的地址).
正如您所指出的,引用不能反弹(由于它们的值赋值语义),但reference_wrapper<T>类模板可以反弹,因为它具有引用赋值语义.这是因为它reference_wrapper<T>被设计为与STL容器和算法一起使用,并且如果其复制赋值运算符与其复制构造函数不同,则不会正常运行.但是,reference_wrapper<T>仍然具有值比较语义,如引用,因此当与STL容器和算法一起使用时,它与指针的行为非常不同.例如,set<T*>可以包含指向具有相同值的不同对象的指针,同时set<reference_wrapper<T>>可以包含对具有给定值的一个对象的引用.
所述not_null<T*>类模板具有参考分配和比较的语义,比如一个指针; 它是一种类似指针的类型.这意味着当与STL容器和算法一起使用时,它的行为类似于指针.它不能为空.
所以,除了忘记比较语义之外,你的评估是正确的.并且,reference_wrapper<T>不会被任何类型的指针类型淘汰,因为它具有类似引用的值比较语义.
Jen*_*ens 10
我认为仍有一些用例std::reference_wrapper未被覆盖gsl::not_null.基本上,std::reference_wrapper镜像引用并具有operator T&转换,同时not_null具有指针接口operator->.我想到的一个用例是在创建线程时:
void funcWithReference(int& x) { x = 42; }
int i=0;
auto t = std::thread( funcWithReference, std::ref(i) );
Run Code Online (Sandbox Code Playgroud)
如果我无法控制funcWithReference,我就无法使用not_null.
这同样适用于算法的仿函数,我也必须使用它进行绑定boost::signals.