ROS C++ 規范概要


一、動機

代碼一致才能可讀、聯調、高效率、高復用、可移植性。

 

二、命名方式

CamelCased

camelCased

under_scored

ALL_CAPITALS

2.1 Package命名方式:under_scored

2.2 Topics / Services命名方式:under_scored

2.3 Files命名方式:under_scored

比如:hokuyo_topurg_laser.cpp、hokuyo_topurg_laser.hpp

如果是類文件,那么命名方式迎合類名,比如:ActionServer類,那么action_server.h

2.3.1 lib命名方式:under_scored

不要在lib后面插入下划線,比如:

lib_my_great_thing ## Bad
libmy_great_thing ## Good

2.4 Classes / Types命名方式:CamelCased

比如:class ExampleClass

如果名字中有縮寫,那么全部大寫:class HokuyoURGLaser

2.5 Function / Methods

函數名稱和類的方法:camelCased,參數采用:under_scored

2.6 Variables

一般采用under_scored。合理描述變量,不要表達不清。

迭代變量,比如:for(int i = 0; …),可以用短變量i, j, k;應用順序保證為i,j,k。

STL 迭代變量,必須標明STL變量的類型如:

std::list<int> pid_list;
std::list<int>::iterator pid_it;

STL迭代器的可以用自身類型表示

std::list<int> pid_list;
std::list<int>::iterator int_it;

2.6.1 Constant命名方式:ALL_CAPITALS

2.6.2 Member variables命名方式:under_scored_

2.6.3 Global variables命名方式:g_under_scored

2.7 Namespaces命名方式:under_scored

 

三、License statements

在頭文件與源文件的開頭都要包含Copyright,比如:

Copyright (c) 2019 Fujian(Quanzhou)-HIT Research Institute of Engineering and Technology All rights reserved.

解釋一下,©是版權的意思,也可以寫成(c);2019表示代碼完成時間;Fujian(Quanzhou)-HIT Research Institute of Engineering and Technology 泉州工研院;All rights reserved表示保留所有權利。

也可以寫成:

Copyright (c) 2019-2020 Fujian(Quanzhou)-HIT Research Institute of Engineering and Technology All rights reserved.

2019-2020表示意思完成時間是2008年,最近一次修訂在2011年。

 

四、Formatting

IDE應該可以處理大量的格式化事情。建議采用VSCode。

縮進為2個空格,不用tab鍵。Namespaces不縮進

比如:

if(a < b)
{
  // do stuff
}
else
{
  // do other stuff
}

單行可以不用括號,符號連接如下:

if(a < b)
  x = 2 * a;

if(a < b)
{
  for(int i = 0; i < 10; i++)
    PrintItem(i);
}

下面給出一個完整的例子:

/*
 * A block comment looks like this...
 */
#include <math.h>
class Point
{
public:
  Point(double xc, double yc) :
    x_(xc), y_(yc)
  {
  }
  double distance(const Point& other) const;
  int compareX(const Point& other) const;
  double x_;
  double y_;
};
double Point::distance(const Point& other) const
{
  double dx = x_ - other.x_;
  double dy = y_ - other.y_;
  return sqrt(dx * dx + dy * dy);
}
int Point::compareX(const Point& other) const
{
  if (x_ < other.x_)
  {
    return -1;
  }
  else if (x_ > other.x_)
  {
    return 1;
  }
  else
  {
    return 0;
  }
}
namespace foo
{
int foo(int bar) const
{
  switch (bar)
  {
    case 0:
      ++bar;
      break;
    case 1:
      --bar;
    default:
    {
      bar += bar;
      break;
    }
  }
}
} // end namespace foo

4.1 每行字符數:120個字符以內

4.2 頭文件格式

防止重復調用,采用以下格式:

#ifndef PACKAGE_PATH_FILE_H
#define PACKAGE_PATH_FILE_H
...
#endif

 

五、文檔

所有程序必須有文檔,而且采用doxygen建立文檔。

 

六、控制台輸出

盡量不采用printf與cout,采用 rosconsole作為輸出。

 

七、宏

避免使用宏定義,與inline與const不同,宏既不是類型,也不是作用域。

 

八、預處理指令(#if vs. #ifdef)

對於條件編譯,我們采用#if,不采用#ifdef。

比如:

#ifdef DEBUG
        temporary_debugger_break();
#endif

如果我們想關閉DEBUG,那么會輸入:

cc -c lurker.cpp -DDEBUG=0

如果采用:

#if DEBUG
        temporary_debugger_break();
#endif

即使DEBUG沒有定義,也可以用。

 

九、輸出參數

用於輸出的參數采用指針,而不是引用。比如:

int exampleMethod(FooThing input, BarThing* output);

 

十、Namespaces

非常建議大家使用命名空間來指定代碼的作用域,根據package的名字來命名namespace

不采用using-directive,比如

using namespace std; // Bad, because it imports all names from std::

采用using-declarations,比如:

using std::list;  // I want to refer to std::list as list
using std::vector;  // I want to refer to std::vector as vector

 

十一、繼承

采用virtual表示多態,不采用多重繼承

 

十二、異常處理

異常處理采用error-report機制,而不采用返回整形值。比如:

在document記錄在packages中function/method產生的全部異常。

不采用在destructors中調用throw。

不采用在callback方法中調用throw。

如果采用在package中采用錯誤代碼,而非異常處理,請保持代碼始終如一。

12.1 異常處理注意事項:

當您的代碼可以被異常中斷時,您必須確保在堆棧變量超出范圍時將釋放您保留的資源。 特別是,必須釋放互斥鎖,並且必須釋放堆分配的內存。 

 

十三、Enumerations(枚舉類型)

用namespace控制枚舉類型:

namespace Choices
{
  enum Choice
  {
     Choice1,
     Choice2,
     Choice3
  };
}
typedef Choices::Choice Choice;

 

十四、Globals(全局類型)

不采用全局變量以及全局函數。

 

十五、Static class variables(靜態成員變量)

不采用靜態成員變量。

 

十六、調用exit()函數

僅在程序出口調用exit()函數。

在lib中不采用exit()函數。

 

十七、Assertions()

 采用assert檢查前提條件,數據結構完整性以及內存分配器的返回值。 assert比編寫條件語句更好,條件語句很少(如果有的話)被執行。

不采用直接調用assert(),而采用ros/assert.h

/** ROS_ASSERT asserts that the provided expression evaluates to
 * true.  If it is false, program execution will abort, with an informative
 * statement about which assertion failed, in what file.  Use ROS_ASSERT
 * instead of assert() itself.
 * Example usage:
 */
   ROS_ASSERT(x > y);
/** ROS_ASSERT_MSG(cond, "format string", ...) asserts that the provided
 * condition evaluates to true.
 * If it is false, program execution will abort, with an informative
 * statement about which assertion failed, in what file, and it will print out
 * a printf-style message you define.  Example usage:
 */
   ROS_ASSERT_MSG(x > 0, "Uh oh, x went negative.  Value = %d", x);
/** ROS_ASSERT_CMD(cond, function())
 * Runs a function if the condition is false. Usage example:
 */
   ROS_ASSERT_CMD(x > 0, handleError(...));
/** ROS_BREAK aborts program execution, with an informative
 * statement about which assertion failed, in what file. Use ROS_BREAK
 * instead of calling assert(0) or ROS_ASSERT(0). You can step over the assert
 * in a debugger.
 * Example usage:
 */
   ROS_BREADK();

不要在assert中做工作; 只檢查邏輯表達式。 根據編譯設置,可能無法執行斷言。

 

十八、Testing

 見gtest.

 

十九、Portability(可以移植性)

目前ros支持linux與XOS之間的移植,需要注意:

(1)不采用uint,采用unsigned int

(2)調用isnan()使用std::isnan()

 

二十、Deprecation(移除不用的代碼)

如果移除包中的頭文件,應在頭文件加入警告:

#warning mypkg/my_header.h has been deprecated

如果移除函數,添加不推薦使用屬性:

ROS_DEPRECATED int myFunc();

如果移除一個類,請移除其構造函數和任何靜態函數:

class MyClass
{
public:
  ROS_DEPRECATED MyClass();

  ROS_DEPRECATED static int myStaticFunc(); 
};

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM