safe-rules icon indicating copy to clipboard operation
safe-rules copied to clipboard

详细的C/C++编程规范指南,由360质量工程部编著,适用于桌面、服务端及嵌入式软件系统。

Results 11 safe-rules issues
Sort by recently updated
recently updated
newest added

> 示例 >```cpp >struct T { > int i; > > int foo() { return i; } > int bar() { return 0; } > > static int baz(); >};...

> 失去对已分配资源的控制 其实单看这个,线程 `detach()` 也算是失去控制了。 [`std::thread::detach`](https://link.zhihu.com/?target=https%3A//zh.cppreference.com/w/cpp/thread/thread/detach),线程对象释放了自己的资源(线程)的所有权,允许线程执行独立地持续。 不过可以保证一旦该线程退出,**则释放任何分配的资源**。 并不会有原文中说的: > 对于动态分配的资源,其地址、句柄或描述符等标志性信息不可被遗失,否则资源无法被访问也无法被回收,这种问题称为“***资源泄漏***”,会导致资源耗尽或死锁等问题,使程序无法正常运行。 之类的问题。 或许是标题中的 “不可失去对已分配资源的控制”,中没有明确是“***谁***”失去了对资源的控制? 线程 `detach()` 之后,我们的确失去了对此线程的控制,之后的合法性由 `OS` 保证,这或许不是什么问题。 当然,我不是推崇 `detach()`,它本身也有不少问题,[如](https://github.com/Mq-b/Loser-HomeWork/issues/190)。 --- 总而言之,或许我觉得此规则可以增加一些描述,明确是“谁”失去了资源的控制,或者即使失去,如果有保证正确,也无所谓。

原文: >应改为: >```cpp >namespace U { > const float PI = 3.14F; // Compliant >} > >namespace V { > const long double PI = 3.14159L; // Compliant >} ---...

原文: > std::move 宣告对象的数据即将被转移到其他对象,转移之后对象在逻辑上不再有效,不应再被使用。 单看这句话并无什么太过分的问题,但是主要在于:类似的*话术*传播非常广泛和深远,让人对于移动语义和 `std::move` 抱有了很多**不切实际的幻想,认为它是编译器做了什么魔法,`std::move` 了就不能再使用**。 原文描述本身并无太大问题,但是我认为总归还是可以改进的,前半句是没有太多问题的,也是一种“***君子协定***”,让开发者们约定了,自己定义的类的移动构造、移动赋值等函数,是转移资源所有权。 这里的重点在于移动构造、移动赋值等函数,而非是 `std::move` 本身,std::move 实际几乎什么也没做,**它只是将左值表达式转换到亡值表达式,用以匹配移动构造、移动赋值等函数**; “移动”,是 `std::move` 的语义上的,而非实际作用上的。 原文描述的:“*std::move 宣告对象的数据即将被转移到其他对象*”,这里“**宣告**”,其实就是指的语义上的“移动”,一种暗示,我能明白其表达含义。 --- 总而言之,我认为应该强调: 1. 移动之后的对象,它的状态取决于移动构造、移动赋值等函数本身的实现,而非是编译器魔法,到底能否重新使用,也取决于各位的实现,通常来说,重新对对象进行初始化,是可以再次正确使用的。 2. std::move 本身。 虽然这可能让此规则不那么简洁,但是对后人来说,大大减小难度,也可以避免中文互联上的无数的对移动语义的错误信息传播误导。

> Copyright [yyyy] [name of copyright owner] 空缺这个是故意为之吗?

[48. 对有符号整数进行超出取值范围的左移运算](https://github.com/Qihoo360/safe-rules/blob/a0c63a935476dbf59d38cbf4a5c7b59752b7e3b0/cpp-ub-list.md#48-%E5%AF%B9%E6%9C%89%E7%AC%A6%E5%8F%B7%E6%95%B4%E6%95%B0%E8%BF%9B%E8%A1%8C%E8%B6%85%E5%87%BA%E5%8F%96%E5%80%BC%E8%8C%83%E5%9B%B4%E7%9A%84%E5%B7%A6%E7%A7%BB%E8%BF%90%E7%AE%97) 这里的未定义行为在 C++20 移除了,见 [P1236R1](https://wg21.link/p1236r1)。

问题来自提交 https://github.com/Qihoo360/safe-rules/commit/69bba35f4cef3eb4bc303c60fd161a430ef9adb1 。 C++ 标准中将 C 头文件设为弃用是历史错误,因为大部分 C 头文件并不是待移除的候选。 C++23 更正了这个问题,见 [WG21 P2340R1](https://wg21.link/p2340r1)。 现在的推荐应该是 > The intended use of these headers is for interoperability only. It is possible that C++...

原文: > 使用 nullptr、NULL、0 等常量初始化的指针是空指针 应改为:“使用 nullptr、NULL、0 这些*空指针常量*初始化的指针是空指针”。 建议强调“空指针常量”,其实考虑字面量这种说法似乎也可行。 “**等**”,事实上没有额外的空指针常量了。 这里的“**等**”不可能表达的是:“*[零初始化](https://zh.cppreference.com/w/cpp/language/zero_initialization)和[值初始化](https://zh.cppreference.com/w/cpp/language/value_initialization)也初始化指针为它对应的空值。*” 除非表达的是:“*[std::nullptr_t](https://zh.cppreference.com/w/cpp/types/nullptr_t) 类型的纯右值*”,然而它通常就是 `nullptr`。除非......: ```cpp int* p = std::nullptr_t{}; ``` 然而感觉这也不太可能是原文表达的“常量”。 --- 写了半天感觉莫名其妙,因为可以简单的描述: > **空指针是值为空的指针(通常使用空指针字面量 nullptr,或空指针常量 0、NULL 进行初始化)** 之前提过:https://github.com/Qihoo360/safe-rules/pull/32

在阅读 [▌R2.5 资源的分配与回收方法应成对提供](https://github.com/Qihoo360/safe-rules/blob/main/c-cpp-rules.md#user-content-incompletenewdeletepair) 这一节内容的时候,我注意到了一个用词:“**堆栈**”。 这是一个在中文互联网极其常见,又古老的词语,那么“**堆栈**”到底是“*堆*”(heap)还是“*栈*”(stack),又或者是“*堆+栈*”(heap+stack)? 据我所知,通常来说它在指:“***栈***”。这种用词毫无逻辑且经不起推敲,纯属历史遗留,应当改正。

https://github.com/Qihoo360/safe-rules/blob/60fec0a21d3c7da20dcf78c51134089a073bcb3f/c-cpp-rules.md?plain=1#L5943-L5957 “***foo(100) 相当于将 100 隐式转为 String 类的对象,这种隐式转换是怪异的,也往往意味着意料之外的错误***” 这是不对的,事实上我认为也展示不出所谓的怪异,准确的说是 **`100` 用于调用转换构造函数,构造出一个临时的 String 对象,再用来初始化函数 foo 的形参,大约类似于 `foo(String(100))`** 。如果还未达到 C++17,没有强制的复制消除,则还需要重载决议选择,走一个移动构造或者复制构造。也就是总归有两次构造。 简单来说 ```cpp #include class String { public: String(int capacity) {}; String(const String&) =...