C++ 之 【小贴士】

1. 基本类作为友元类,其在使用前可不预先声明。但模板类作为友元类,其在使用前必须预先声明。

template <typename T> class SmartPtr; //模板类作为友元时要先有声明   

template <typename T> class RefPtr
{
private:    
    friend class SmartPtr<T>; 
    ……
}

2. 脱离函数使用的花括号依然实现了括号内所声明变量的作用域限制在括号内

{
    shared_ptr sptr1(pa);
    {
        shared_ptr sptr2(sptr1);        
        {
            shared_ptr sptr3=sptr1;
        }       
    }    
}

        上述三个变量的作用域分别在三个花括号内

3. 不能使用字符或者整数去初始化字符串。

std::string s('x');    //错误
std::string s(1, 'x');    //正确

4. string 类的所有成员函数

函数名称功能
构造函数产生或复制字符串
析构函数销毁字符串
=,assign赋以新值
Swap交换两个字符串的内容
+ =,append( ),push_back()添加字符
insert ()插入字符
erase()删除字符
clear ()移除全部字符
resize ()改变字符数量
replace()替换字符
+串联字符串
==,! =,<,<=,>,>=,compare()比较字符串内容
size(),length()返回字符数量
max_size ()返回字符的最大可能个数
empty ()判断字符串是否为空
capacity ()返回重新分配之前的字符容量
reserve()保留内存以存储一定数量的字符
[],at()存取单一字符
>>,getline()从 stream 中读取某值
<<将值写入 stream
copy()将内容复制为一个 C - string
c_str()将内容以 C - string 形式返回
data()将内容以字符数组形式返回
substr()返回子字符串
find()搜寻某子字符串或字符
begin( ),end()提供正向迭代器支持
rbegin(),rend()提供逆向迭代器支持
get_allocator()返回配置器

5.参加比较的两个字符串,任一字符串均不能为 NULL,否则程序会异常退出。

6. 注意一下vector,string等对内存的操作

        比如vector的clear不清空内存,采用操作符[]依然能访问清空前的数据(不过其成员函数at就会先检测长度,不允许越界访问),string重新赋值,即使长度小于之前,采用操作符[]依然能访问大于当前长度的原位置数据。

7. find()实现字符串正向查找,rfind()实现字符串逆向查找(仅查找方向为由后向前,但字符串匹配还是正向匹配)

        此外,find_first_of 函数最容易出错的地方是和find函数搞混。它最大的区别就是如果在一个字符串str1中查找另一个字符串str2,如果str1中含有str2中的任何字符,则就会查找成功,而find必须str2全部包含在str1中。

        而rfind和find_last_of除同样有上述区别外,rfind会找出序号最靠前的,而find_last_of会找出最先被找到的。

        还有find_first_not_of()函数和 find_last_not_of(),根据字面即可理解。

8. 配置器

        配置器最早是为将内存模型抽象化而提出的。所以使用内存配置器分配内存时,是按对象的个数进行的,而不是按字节数。这有别于原来的 new [] 和 new 操作符。配置器最大的优点在于,配置器实现了将算法、容器与物理存储细节分隔。配置器可以提供一套分配与释放内存的标准方式,并提供用作指针类型和引用类型的标准名称。目前而言,配置器仅是一种纯粹的抽象。行为上类似分配器的类型都可看作配置器。

9. 序列容器

        序列容器以线性序列的方式存储元素。它没有对元素进行排序,元素的顺序和存储它们的顺序相同

9.1.array<T,N> (数组容器) :
        是一个长度固定的序列,有 N 个 T 类型的对象,不能增加或删除元素。

9.2.vector<T> (向量容器) :
        是一个长度可变的序列,用来存放T类型的对象。必要时,可以自动增加容量,但只能在序列的末尾高效地增加或删除元素。比如想删除中间元素,高效的做法是将该元素赋值为末尾元素,然后删除末尾元素,但是该做法打乱顺序。

9.3.deque<T> (双向队列容器) :
        是一个长度可变的、可以自动增长的序列,在序列的两端都不能高效地增加或删除元素。

9.4.list<T> (链表容器) :
        是一个长度可变的、由 T 类型对象组成的序列,它以双向链表的形式组织元素,在这个序列的任何地方都可以高效地增加或删除元素。访问容器中任意元素的速度要比前三种容器慢,这是因为 list<T> 必须从第一个元素或最后一个元素开始访问,需要沿着链表移动,直到到达想要的元素。

9.5.forward list<T> (正向链表容器) :
        是一个长度可变的、由 T 类型对象组成的序列,它以单链表的形式组织元素,是一类比链表容器快、更节省内存的容器,但是它内部的元素只能从第一个元素开始访问。

10. 数组越界访问

        编译器不检查不报错,运行时有可能崩溃,有可能不崩溃但拿到一个错误值。比如二维数组a[ ][ ]第二维越界时会访问到第二行数据,因为二维数组其实是一维存储的,并且a[0]将输出整个二维数组。又比如类中有一个KDL::Frame frame_before成员和一个紧挨的KDL::Frame frame[]数组, frame[-1]将访问到frame_before,因为类中成员是按声明顺序开辟内存的。

11. array容器

        array<T,N> 模板定义了一种相当于标准数组的容器类型,N 个 T 类型元素,不能增加或删除元素。模板实例的元素被内部存储在标准数组中。和标准数组相比,array 容器的额外幵销很小,但提供了两个优点:如果使用 at(),当用一个非法的索引访问数组元素时,能够被检测到,因为容器知道它有多少个元素。这也就意味着数组容器可以作为参数传给函数,而不再需要单独去指定数组元素的个数。初始化跟标准数组一样。成员函数fill(value) 函数将所有元素都设为传入的value。

12. std::begin(a)等同于a.begin(),std::end(a)等同于a.end().

13. 指针使用sizeof()注意

        定义一个指针p,sizeof(p)表示指针占内存大小,32位机4字节,64位机8字节。sizeof(*p)才是指针指向数据的内存大小

14. typedef使用注意

        typedef它是将其后面的整体起了一个别名,该整体可能由数据类型和声明符修饰,但是别名的对象是被修饰的对象。故:

typedef char *pstring;
const pstring cstr = 0;

        这样的情况,pstring不能被简单替换看成 const char *cstr 而被当成指向常量的指针,实为 char *const cstr 一个const指针。

15. sizeof(), 容器.size()

        使用上述函数时,要注意其返回值为无符号数,若用于表达式,最好先强制类型转换为有符号数,避免负数被强制转换为无符号数成为一个极大值。

16. 头文件中定义变量

        首先,头文件中是不能定义变量的,如果实在要使用公共的全局变量(非公共的全局变量用static或者const修饰定义就行),头文件中用extern声明一个,然后在某一源文件中将其定义,其余使用到该全局变量的源文件包含该头文件。

17. 打印指针

正常的“cout<<指针名”将输出内存地址,但char* 指针不是,而是指针所指向的内存中存放的内容,直到读到“/0”结束标志结束。需要“cout<<&指针名”才是输出内存地址。使用char型指针要注意,防止被处理成字符串

#include <iostream>
using namespace std;
int main()
{
 char *str = "this is a test";
 cout << "str=" << str << endl;
 cout << "*str=" << *str << endl;
 cout << "&str" << &str << endl;
 system("pause");
 return 1;
}

输出:

18. 深拷贝,浅拷贝(*)

        在调用了类的拷贝构造函数、默认拷贝构造函数、重载的“=”这些函数或重载符号给类赋值时,要搞清楚其机理是深拷贝还是浅拷贝。此外,容器的元素是类时,也要注意这一点,因为容器在赋值或拷贝时亦需要调用类的上述函数,比如vector元素是opencv的mat类,采用“vector(num,mat)”初始化时,一不小心就调用了浅拷贝,多个mat元素操纵的阵列结果是同一个。类中如果定义了clone函数,其采用的一般是深拷贝机制,但还是要看具体说明。

19. numeric_limits<type>::max()

numeric_limits<type>::max()或numeric_limits<type>::min()返回目标数据类型所能表示的最大值或最小值。如numeric_limits<double>::max()表示最大的double。std::numeric_limits<type>::epsilon()返回目标数据类型能表示的最逼近1的正数和1的差的绝对值。https://blog.youkuaiyun.com/wordwarwordwar/article/details/39344131numeric_limits头文件说明。

20. 代码换行

法一:使用反斜杠

string str = "abcd\
1234";

注意:反斜杠后面不准有任何字符。下一行开头的制表符不包含在整个字符串中,但是下一行开头的空格符包含在整个字符串中。

法二: 使用双引号

string str = "abcd"
"1234";

注意:两个字符串会自动拼接,两个字符串之间可以有任意多个空字符("")和空白字符(空白字符包括空格字符,制表符,换行符)。注意下面的区别:
NULL:没有值
空字符:"",不包含任何字符
空白字符:有空格字符,制表符,换行符

21. 小心多余的分号

        注意不要在代码中有多余的分号,其产生的空语句可能会改变程序结构。

22. 标准算法库

        https://zh.cppreference.com/mwiki/index.php?title=cpp/algorithm&variant=zh-hans

23. stream流

        使用stream流时,要注意while(stream>>a)而不是while(stream),后者会导致对stream末尾重复读取。

24. 类型范围

小心数据溢出。

25. 完整性封装

学习moveit将fcl::CollisionGeometry及其描述封装在一起的做法。

struct FCLGeometry
{
  FCLGeometry()
  {
  }

  FCLGeometry(fcl::CollisionGeometry* collision_geometry, const robot_model::LinkModel* link, int shape_index)
    : collision_geometry_(collision_geometry), collision_geometry_data_(new CollisionGeometryData(link, shape_index))
  {
    collision_geometry_->setUserData(collision_geometry_data_.get());
  }

  FCLGeometry(fcl::CollisionGeometry* collision_geometry, const robot_state::AttachedBody* ab, int shape_index)
    : collision_geometry_(collision_geometry), collision_geometry_data_(new CollisionGeometryData(ab, shape_index))
  {
    collision_geometry_->setUserData(collision_geometry_data_.get());
  }

  FCLGeometry(fcl::CollisionGeometry* collision_geometry, const World::Object* obj, int shape_index)
    : collision_geometry_(collision_geometry), collision_geometry_data_(new CollisionGeometryData(obj, shape_index))
  {
    collision_geometry_->setUserData(collision_geometry_data_.get());
  }

  template <typename T>
  void updateCollisionGeometryData(const T* data, int shape_index, bool newType)
  {
    if (!newType && collision_geometry_data_)
      if (collision_geometry_data_->ptr.raw == reinterpret_cast<const void*>(data))
        return;
    collision_geometry_data_.reset(new CollisionGeometryData(data, shape_index));
    collision_geometry_->setUserData(collision_geometry_data_.get());
  }

  std::shared_ptr<fcl::CollisionGeometry> collision_geometry_;
  CollisionGeometryDataPtr collision_geometry_data_;
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值