【代码规范】Google开源项目风格指南

news2024/11/26 16:39:46

系列综述:
💞目的:本系列是个人整理为了秋招面试的,整理期间苛求每个知识点,平衡理解简易度与深入程度。
🥰来源:材料主要源于Google开源项目风格指南进行的,每个知识点的修正和深入主要参考各平台大佬的文章,其中也可能含有少量的个人实验自证。
🤭结语:如果有帮到你的地方,就点个赞关注一下呗,谢谢🎈🎄🌷!!!
🌈【C++】秋招&实习面经汇总篇


文章目录

    • 0.扉页
      • 译者前言
    • 1.头文件
    • 2.作用域
    • 3. 类
    • // TODO:实力没达到,目前看不懂,待更新
    • 7.命名约定
    • 8.注释
    • 9.格式
    • 参考博客


😊点此到文末惊喜↩︎


0.扉页

译者前言

  1. 统一的编程风格的作用
    • 更容易的接收其他代码贡献者的提交,从而避免给代码阅读者和其他代码提交者造成的困扰
    • 更易于理解代码,方便人脑的模式匹配引擎推断各种标识符的含义
  2. 风格的解释
    • 可读性:风格是可读性的体现,是指导C++编程和文件组织方式的约定
    • 规则:风格是一种避免混乱的方式,规则一定要有权威性和说服力

1.头文件

  1. 头文件应该能够自给自足(self-contained)
    • 解释:已有的头文件可以为项目提供完整的支持,不用再包含额外的头文件
    • 例外:一个文件作为文本插入到代码某处。或者,文件内容实际上是其它头文件的特定平台(platform-specific)扩展部分。这些文件就要用 .inc 文件扩展名。
  2. 防止头文件的多重包含
    • 命名格式:<项目名>_<路径>_<文件名>_H_
    • 要求:所有的头文件
    // 为保证唯一性, 头文件的命名应为所在项目目录的全路径
    // 例如, 项目 foo 中的头文件 foo/src/bar/baz.h 可按如下方式保护:
    #ifndef FOO_BAR_BAZ_H_
    #define FOO_BAR_BAZ_H_
    ...
    #endif // FOO_BAR_BAZ_H_
    
  3. 避免使用前置声明
    • 正确方式:使用 #include 包含需要的头文件
    • 解释:前置声明是类、函数和模板的纯粹声明,没伴随着其定义
  4. 内联函数的使用
    • 函数体十行以内,性能关键的函数鼓励使用内联
    • 内联一个大型代码。可能减弱了指令缓存优化,导致执行更慢
    • 析构和构造函数有隐含的成员和操作,往往比看起来更长,不需要内联
    • 虚函数和递归函数不需要内联
  5. #include 的路径及顺序
    • #include的排序,不同类型间的头文件要插入空行类型内的可以使用字母排序
    // 本文件路径为google-awesome-project/src/foo/internal/Function.cpp
    // 
    // 1.本文件所要实现的头文件
    #include "foo/public/Function.h" // 优先位置
    // 2.C 系统文件
    #include <sys/types.h>
    #include <unistd.h>
    // 3.C++ 系统文件
    #include <hash_map>
    #include <vector>
    // 4.其他库的 .h 文件
    // 5.本项目内的 .h 文件
    #include "base/basictypes.h"
    #include "base/commandlineflags.h"
    #include "foo/public/comment.inc"// 纯文本文件
    

2.作用域

  1. 鼓励在文件内使用命名空间
    • 将全局作用域细分,防止全局作用域的命名冲突
    • 在命名空间的最后注释出命名空间的名字
    • 不要在命名空间 std 内声明任何东西
    • 禁止用内联命名空间
    // .h 文件
    namespace mynamespace {
    
    // 所有声明都置于命名空间中
    // 注意不要使用缩进
    class MyClass {
        public:
        ...
        void Foo();
    };
    } // namespace mynamespace
    
    // .cpp文件
    namespace mynamespace {
    // 函数定义都置于命名空间中
    void MyClass::Foo() {
        ...
    }
    // 鼓励在.cpp文件中使用匿名空间
    namespace {
    ...
    }  // namespace
    
    } // namespace mynamespace
    
    
  2. 定义在同一编译单元的函数, 被其他编译单元直接调用可能会引入不必要的耦合和链接时依赖; 静态成员函数对此尤其敏感. 可以考虑提取到新类中, 或者将函数置于独立库的命名空间内
    // 正确的
    namespace myproject {
    namespace foo_bar {
    void Function1();
    void Function2();
    }  // namespace foo_bar
    }  // namespace myproject
    
    // 错误的
    namespace myproject {
    class FooBar {
     public:
      static void Function1();
      static void Function2();
    };
    }  // namespace myproject
    
  3. 局部变量
    • 尽量声明的同时初始化:局部变量应该作用域尽可能小,距离第一次使用尽可能近
    • 基本变量类型可以作为局部变量:因为有寄存器优化,不会影响性能
    • 在循环前声明循环中要用的局部变量:特别是类的对象,可以避免频繁的构造和析构
    // 好——初始化时声明
    int j = g(); 
    // 坏——初始化和声明分离
    int i;
    i = f(); 
    // 好——声明时初始化
    vector<int> v = {1, 2}; 
    // 坏
    vector<int> v;
    v.push_back(1); 
    v.push_back(2);
    
    // 低效的实现
    for (int i = 0; i < 1000000; ++i) {
        Foo f;                  // 构造函数和析构函数分别调用 1000000 次!
        f.DoSomething(i);
    }
    // 高效的实现
    Foo f;                      // 构造函数和析构函数只调用 1 次
    for (int i = 0; i < 1000000; ++i) {
        f.DoSomething(i);
    }
    
  4. 静态和全局变量
    • 禁止使用类的静态变量:静态变量的构造函数、析构函数和初始化的顺序在 C++ 中是只有部分明确的,甚至随着构建变化而变化,导致难以发现的 bug
    • 要使用尽量在同一编译单元内(self-contained)
    • 多线程中的全局变量 (含静态成员变量) 不要使用 class 类型 (含 STL 容器), 避免不明确行为导致的 bug.
    • 作用域的使用, 除了考虑名称污染, 可读性之外, 主要是为降低耦合, 提高编译/执行效率
    • 尽量不用全局变量, 静态变量, 静态类成员变量, 以及函数静态变量,最好单独形成编译单元

3. 类

  1. 在构造函数中不能调用虚函数:调用是不会重定向到子类的虚函数实现
  2. 不要定义隐式类型转换
    • 单参数构造函数尽量使用explicit 关键字就行修饰,避免隐式转换

// TODO:实力没达到,目前看不懂,待更新


7.命名约定

  1. 通用命名规则
    • 少用缩写:尽可能使用通俗的描述性命名,别心疼空间。
    • 可以使用广为人知的缩写:如 i 表示迭代变量和用 T 表示模板参数常见缩写表
int price_count_reader;    // 无缩写
int num_errors;            // "num" 是一个常见的写法
int num_dns_connections;   // 人人都知道 "DNS" 是什么

int n;                     // 毫无意义.
int nerr;                  // 含糊不清的缩写.
int n_comp_conns;          // 含糊不清的缩写.
int wgc_connections;       // 只有贵团队知道是什么意思.
int pc_reader;             // "pc" 有太多可能的解释了.
int cstmr_id;              // 删减了若干字母.
  1. 文件命名
    • 全部小写
    • 使用_进行分割
    // 示例
    my_useful_class.cc
    http_server_logs.h// 比logs.h好
    
  2. 内联函数定义必须放在 .h 文件中。如果内联函数比较短,就直接将实现也放在 .h 中。
  3. 类、结构体和函数(大驼峰法)
    • 每个单词首字母都大写,但只有一个单词时不大写
    • 缩写的单词, 更倾向于将它们视作一个单词进行首字母大写
    // 类和结构体
    class UrlTable { ...
    class UrlTableTester { ...
    struct UrlTableProperties { ...
    
    // 类型定义
    typedef hash_map<UrlTableProperties *, string> PropertiesMap;
    
    // using 别名
    using PropertiesMap = hash_map<UrlTableProperties *, string>;
    
    // 枚举
    enum UrlTableErrors { ...
    // 函数
    int count()// 只有一个单词时,不大写
    void AddTableEntry()
    void DeleteUrl()
    void OpenFileOrDie()
    void StartRpc()// 不是使用StartRPC()
    
  4. 所有变量 (包括函数参数和成员变量) 和命名空间
    • 一律小写, 单词之间用下划线连接
    // 普通变量命名
    string table_name;  // 好 - 用下划线.
    string tablename;   // 好 - 全小写.
    string tableName;  // 差 - 混合大小写
    // 类数据成员
    class TableInfo {
      ...
     private:
      string table_name_;  // 好 - 后加下划线.
      string tablename_;   // 好.
      static Pool<TableInfo>* pool_;  // 好.
    };
    // 结构体内部的变量
    struct UrlTableProperties {
      string name;
      int num_entries;
      static Pool<UrlTableProperties>* pool;
    };
    // 命名空间
    namespace web_search{
    
    }
    web_search::index_util
    
  5. const声明的常量、枚举命名
    • 在程序运行期间其值始终保持不变的, 命名时以 “k” 开头, 大小写混合
    // const声明的常量
    const int kDaysInAWeek = 7;// 数学中的常量表示为k
    // 枚举命名,宏命名方式可能产生冲突
    enum UrlTableErrors {
        kOK = 0,
        kErrorOutOfMemory,
        kErrorMalformedInput,
    };
    
  6. 函数命名
    • 函数名的每个单词首字母大写
    • 缩写的单词, 更倾向于将它们视作一个单词进行首字母大写
    AddTableEntry()
    DeleteUrl()
    OpenFileOrDie()
    StartRpc()// 不是使用StartRPC()
    
    • 使用全大写,并使用下划线区分
    #define ROUND(x) ...
    #define PI_ROUNDED 3.14
    
  7. 类内的私有数据成员
    • 尾下划线的变量命名方式
class Test{
public:
	int FunTest();
private:
	int word_;// 下划线在开始位置是系统内部的变量
};

8.注释

  1. 注释一定要慷慨,因为需要给下一个阅读你代码的人看(下一个阅读的人大概率是你自己!6!)
  2. 要公布的项目文件头部应该加入版权公告
    /*
    ** This file is part of LibreBoot progect.(项目归属)
    ** file_name.py - The core part of LibreBoot Progect (文件名和作用概述)
    ** Copyright (c) 2023-06-01 WangSen 3045672234@qq.com(项目完成时间和个人信息)
    ** Copyright (c) 2024 WangSen 3045672234@qq.com(在2024年你改了一点)
    ** All rights reserved.
    **
    */
    
  3. 每个类的定义都要附带一份注释,描述类的功能和用法
    // Function:Iterates over the contents of a GargantuanTable.
    // Example:
    //    GargantuanTableIterator* iter = table->NewIterator();
    //    for (iter->Seek("foo"); !iter->done(); iter->Next()) {
    //      process(iter->key(), iter->value());
    //    }
    //    delete iter;
    class GargantuanTableIterator {
      ...
    };
    
  4. 函数注释
    • 声明处的注释描述函数功能
      • 函数的输入输出.
      • 对类成员函数而言: 函数调用期间对象是否需要保持引用参数, 是否会释放这些参数.
      • 函数是否分配了必须由调用者释放的空间.
      • 参数是否可以为空指针.
      • 是否存在函数使用上的性能隐患
      • 如果函数是可重入的, 其同步前提是什么?
    • 定义处的注释描述函数实现
      • 描述使用的特殊技巧和算法
    // Returns an iterator for this table.  It is the client's
    // responsibility to delete the iterator when it is done with it,
    // and it must not use the iterator once the GargantuanTable object
    // on which the iterator was created has been deleted.
    //
    // The iterator is initially positioned at the beginning of the table.
    //
    // This method is equivalent to:
    //    Iterator* iter = table->NewIterator();
    //    iter->Seek("");
    //    return iter;
    // If you are going to immediately seek to another place in the
    // returned iterator, it will be faster to use NewIterator()
    // and avoid the extra seek.
    Iterator* GetIterator() const;
    
  5. 变量注释
    • 通常变量名本身足以很好说明变量用途
    • 类数据成员全局变量通常要进行注释
    • 变量特殊值含义(nullptr、0、-1等)需要进行注释
    private:
     // Used to bounds-check table accesses. -1 means
     // that we don't yet know how many entries the table has.
     int num_total_entries_;
    
  6. 实现注释
    • 对于代码中巧妙的, 晦涩的, 有趣的, 重要的地方加以注释
    • 多行注释可以使用Tab进行对齐
    • 不要描述显而易见的现象,最好描述是代码自身的描述
    DoSomething();                  // Comment here so the comments line up.
    DoSomethingElseThatIsLonger();  // Two spaces between the code and the comment.
    { // One space before comment when opening a new scope is allowed,
      // thus the comment lines up with the following comments and code.
      DoSomethingElse();  // Two spaces before line comments normally.
    }
    std::vector<string> list{
                        // Comments in braced lists describe the next element...
                        "First item",
                        // .. and should be aligned appropriately.
    "Second item"};
    DoSomething(); /* For trailing block comments, one space is fine. */
    
  7. 不完美代码的注释
    • 使用 TODO 注释表示将来某一天做某事
    // TODO(kl@gmail.com): Use a "*" here for concatenation operator.
    // TODO(Zeke) change this to use relations.
    // TODO(bug 12345): remove the "Last visitors" feature
    
  8. 弃用注释
    • 写上包含全大写的// DEPRECATED的注释, 以标记某接口为弃用状态. 注释可以放在接口声明前, 或者同一行.

9.格式

  1. 每一行代码字符数不超过 80,因为80列宽是传统标准
  2. 尽量不使用非 ASCII 字符, 使用时必须使用 UTF-8 编码
  3. 制表符
    • 使用两个空格缩进代替Tab
    • 应该设置编辑器将制表符转为空格
  4. 函数声明与定义
    • 函数形参用, + 空格进行区分
    • ) {直接加空格
    • 形参放下,可以分行放置
    • 左圆括号总是和函数名在同一行
    • 函数名和左圆括号间永远没有空格
    • 必须添加形参名
    ReturnType LongClassName::ReallyReallyReallyLongFunctionName(// 没有空格
        Type par_name1,  // 4个空格
        Type par_name2,
        Type par_name3) {// 注意空格
      DoSomething();  // 函数体两个空格
      ...
    }
    
  5. 匿名函数
    int x = 0;
    auto add_to_x = [&x](int n) { x += n; };
    
  6. if表达式
    if (condition) {  // 圆括号里没有空格.
      ...  // 2 空格缩进.
    } else if (...) {  // else 与 if 的右括号同一行.
      ...
    } else {
      ...
    }
    // 只要其中一个分支用了大括号, 两个分支都要用上大括号.
    if (condition) {
      foo;
    } else {
      bar;
    }
    // 简短语句
    if (x == kFoo) return new Foo();
    
  7. switch语句
    switch (var) {
      case 0: {  // 2 空格缩进
        ...      // 4 空格缩进
        break;
      }
      case 1: {
        ...
        break;
      }
      default: {
        assert(false);
      }
    }
    
  8. 循环语句
    while (condition) {// 圆括号前后都有空格
      doing();
    }
    for (int i = 0; i < kSomeNumber; ++i) {// 圆括号前后都有空格
      doing();
    } 
    
  9. 指针和引用表达式
    • 声明时空格前置,使用时没有空格
    x = *p;
    p = &x;
    x = r.y;
    x = r->y;
    // 空格前置
    char *c, *a;
    const string &str;
    
  10. 普通的双目运算符
    • 加减乘除等两边都要加空格
  11. 初始化
    int x = 3;
    int x(3);
    int x{3};
    string name("Some Name");
    string name = "Some Name";
    string name{"Some Name"};
    
  12. 预处理指令位于缩进代码块中, 指令也应从行首开始
    // 好 - 指令从行首开始
      if (lopsided_score) {
    #if DISASTER_PENDING      // 正确 - 从行首开始
        DropEverything();
    # if NOTIFY               // 非必要 - # 后跟空格
        NotifyClient();
    # endif
    #endif
        BackToNormal();
      }
    
  13. 类格式
    // .h头文件
    class MyClass : public OtherClass {// 注意空格
     public:      // 注意有一个空格的缩进
      // 公有的构造函数和析构函数
      MyClass();  // 标准的两空格缩进
      explicit MyClass(int var);// 单参构造函数的explicit声明
      ~MyClass() {}
      // 其他函数
      void SomeFunction();
      void SomeFunctionThatDoesNothing() {
      	doing();
      }
      void set_some_var(int var) { some_var_ = var; }
      int some_var() const { return some_var_; }
      
     protected:
      // public 放在最前面, 然后是 protected, 最后是 private
      
     private:
      // 函数部分
      bool SomeInternalFunction();
      // 数据部分:尾下划线法
      int some_var_;
      int some_other_var_;
    };
    // .cpp实现文件
    
    // 如果不能放在同一行,
    // 必须置于冒号后, 并缩进 4 个空格
    MyClass::MyClass(int var)
        : some_var_(var), some_other_var_(var + 1) {
      DoSomething();
    }
    
    // 如果初始化列表需要置于多行, 将每一个成员放在单独的一行
    // 并逐行对齐
    MyClass::MyClass(int var)
        : some_var_(var),             // 4 space indent
          some_other_var_(var + 1) {  // lined up
      DoSomething();
    }
    
    // 右大括号 } 可以和左大括号 { 放在同一行
    // 如果这样做合适的话
    MyClass::MyClass(int var)
        : some_var_(var) {}
    
    
  14. 命名空间不要增加额外的缩进层次
    // 单命名空间
    namespace {
    
    void foo() {  // 正确. 命名空间内没有额外的缩进.
      ...
    }
    
    }  // namespace
    // 嵌套命名空间
    namespace foo {
    namespace bar {
    


少年,我观你骨骼清奇,颖悟绝伦,必成人中龙凤。
不如点赞·收藏·关注一波


🚩点此跳转到首行↩︎

参考博客

  1. 版权规范
  2. 待定引用
  3. 待定引用
  4. 待定引用
  5. 待定引用
  6. 待定引用
  7. 待定引用
  8. 待定引用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/598553.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于卡尔曼滤波实现线性目标跟踪

文章目录 前言卡尔曼滤波基本推导运算 实现目标检测卡尔曼预测器ID分配器&#xff08;跟踪器&#xff09; 完整代码代码总结 前言 一个需求&#xff0c;在一个稳定的场景当中&#xff0c;实现目标检测计数算法。 任务点&#xff1a; 实现目标检测完成对不同类别的物品进行计数…

Three.js--》实现3d字体模型展示

目录 项目搭建 初始化three.js基础代码 设置环境纹理 加载字体模型 今天简单实现一个three.js的小Demo&#xff0c;加强自己对three知识的掌握与学习&#xff0c;只有在项目中才能灵活将所学知识运用起来&#xff0c;话不多说直接开始。 项目搭建 本案例还是借助框架书写…

前后端交互模型http协议Ajax简介

0、前言&#xff1a;本文只是对“前后端交互模型&http协议&Ajax简介”当中的理论&#xff0c;作用&#xff0c;方法进行总结说明&#xff0c;用于回顾知识&#xff0c;做概括总结&#xff0c;没有具体实现代码。 1、前后端交互模型&#xff1a; 前端发送请求&#xff…

信号机制上(信号概念、发送、定时器、信号捕捉、SIGCHLD)

一、信号机制 概念&#xff1a;信号是在软件层次上对中断机制的一种模拟&#xff0c;是一种异步通信方式 所有信号的产生及处理全部都是由内核完成的 信号的产生&#xff1a; 1 按键产生 2 系统调用函数产生&#xff08;比如raise&#xff0c; kill&#xff09; 3 硬件异…

连接MQTT服务端

MQTT客户端之间要想实现通讯&#xff0c;必须要通过MQTT服务端。因此MQTT客户端无论是发布消息还是订阅消息&#xff0c;首先都要连接MQTT服务端。 MQTT客户端连接服务端一共有两步。 第一步&#xff08;CONNECT请求&#xff09; 首先MQTT客户端将会向服务端发送连接请求。该…

HBase 的关键流程解析

前言 本文隶属于专栏《大数据技术体系》&#xff0c;该专栏为笔者原创&#xff0c;引用请注明来源&#xff0c;不足和错误之处请在评论区帮忙指出&#xff0c;谢谢&#xff01; 本专栏目录结构和参考文献请见大数据技术体系 正文 HBase 客户端会将查询过的 HRegion 的位置信息…

【Python爬虫】采集电商商品评价信息

目录 一、数据采集逻辑二、数据Schema三、数据爬取1.导入库2.对爬虫程序进行伪装3.抓取商品评论信息4.防止反爬&#xff0c;每爬取一页数据后&#xff0c;设置程序休眠环节 四、数据存储1. 存储到csv 2.存储到数据库 一、数据采集逻辑 在进行数据采集之前&#xff0c;明确哪些…

Linux下C语言文件描述符操作(dup / dup2 / sendfile / splice / tee)

Linux的哲学是一切皆文件&#xff0c;而操作文件是通过文件描述符来进行。本文梳理一下dup / dup2 / sendfile / splice/ tee函数对文件描述符的操作。 目录 1.dup 2.dup2 3.sendfile 4.splice 5.tee 1.dup #include <unistd.h> int dup(int fd); 复制一个现有的…

Java基础(maven)——maven新建项目 常用IO工具 Durid数据库工具 案例

目录 引出用Maven建项目0.Maven配置方式1.io流的工具IOUtils/FileUtils1&#xff09;可以读文件、按照行读、读网页等&#xff1b;2&#xff09;配合hasmap进行简体繁体转换 2.durid数据库连接工具1&#xff09;创建连接&#xff0c;durid进行连接管理2&#xff09;查询的方式q…

chatgpt赋能python:Python中的转置函数-一种简单而高效的矩阵操作

Python中的转置函数 - 一种简单而高效的矩阵操作 作为一名10年的Python编程经验工程师&#xff0c;掌握利用Python进行矩阵操作是必不可少的。Python中提供了各种高效的矩阵操作功能&#xff0c;其中之一就是转置函数。 什么是转置&#xff1f; 在数学中&#xff0c;矩阵转置…

追寻幸福:探索幸福的关键特征和行为

目录 1. 积极的心态 2. 良好的人际关系 3. 自我接纳和自尊 4. 追求意义和目标 5. 健康的身心状态 6. 感知和实现个人价值 幸福是一个主观的感受&#xff0c;因此不同的人对于幸福的定义和追求方式可能会有所不同。然而&#xff0c;有一些共同的特点和行为模式&#xff0c…

【数据结构】难度上一个台阶的二叉树实现

【数据结构】难度上一个台阶的二叉树实现 一、什么是树和二叉树&#xff1f;二、目标三、实现3.1、初始化工作3.2、二叉树的前序遍历3.2.1、原理图解3.2.2、代码实现 3.3、二叉树的创建3.3.1、原理解析3.3.2、代码实现 3.4、二叉树的中序遍历3.5、二叉树的后序遍历3.6、二叉树的…

K8S系列文章之快速入门K8S

搭建K8S环境 前置 目前生产部署Kubernetes 集群主要有两种方式&#xff1a; kubeadm Kubeadm 是一个K8s 部署工具&#xff0c;提供kubeadm init 和kubeadm join&#xff0c;用于快速部署Kubernetes 集群。 官方地址&#xff1a;https://kubernetes.io/docs/reference/setu…

ChatGPT出来后,为什么老有人想让我们程序员失业?

&#x1f431; 个人主页&#xff1a;不叫猫先生&#xff0c;公众号&#xff1a;前端舵手 &#x1f64b;‍♂️ 作者简介&#xff1a;2022年度博客之星前端领域TOP 2&#xff0c;前端领域优质作者、阿里云专家博主&#xff0c;专注于前端各领域技术&#xff0c;共同学习共同进步…

【LeetCode每日一题】——1248.统计「优美子数组」

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时间频度】九【代码实现】十【提交结果】 一【题目类别】 滑动窗口 二【题目难度】 中等 三【题目编号】 1248.统计「优美子数组」 四【题目描述】 给…

NVIDIA NCCL 源码学习(十)- 多机间ncclSend和ncclRecv的过程

先回忆一下单机的执行流程&#xff0c;用户执行ncclSend之后通过ncclEnqueueCheck将sendbuff&#xff0c;sendbytes&#xff0c;peer等信息保存到了comm->p2plist中&#xff1b;然后执行ncclGroupEnd&#xff0c;如果发现channel没有建立到peer的链接则先建链&#xff0c;然…

深入理解设计原则之接口隔离原则(ISP)

系列文章目录 C高性能优化编程系列 深入理解设计原则系列 深入理解设计模式系列 高级C并发线程编程 LSP&#xff1a;接口隔离原则 系列文章目录1、接口隔离原则的定义和解读2、案例解读3、如何判断一个接口是否符合接口隔离原则&#xff1f;小结 1、接口隔离原则的定义和解读…

网络工程师一定要会关键技能:如何进行IP子网划分?

对于所有从事IP网络方面工作的工程师来说&#xff0c;进行IP子网划分操作属于一个必备的关键技能&#xff0c;也属于必须掌握的专业内容&#xff1b;但对于初学者来说&#xff0c;真正理解IP子网划分的概念也是一件相当困难的事情。 怎样才能正确地进行子网划分操作 IP子网划…

影响现代办公室隔断设计的因素有哪些,办公室隔断设计方案要求

影响现代办公室隔断设计的因素有哪些 1. 办公空间的用途和功能要求 2. 员工数量及工作场所的布局 3. 设计风格和企业文化要求 4. 预算和材料选择 5. 环保节能和安全性要求 办公室隔断设计方案要求&#xff1a; 1. 合理利用空间&#xff0c;满足办公室的功能需求 2. 设计…

Creepypastsa VoxEdit 竞赛

召唤所有恐怖都市传闻爱好者。 通过 Creepypasta VoxEdit 竞赛&#xff0c;潜入黑暗领域&#xff0c;并释放你们的创造力&#xff01;踏入阴森恐怖的神秘世界&#xff0c;把你最可怕的噩梦变成现实&#xff01; 设计终极的 Creepypasta 体素资产 你是恐怖大师吗&#xff1f;是一…