本文来自对C++官网中《Published by PVSCoder Sep 16, 2016 (last update: Sep 16, 2016) How to avoid bugs using modern C++》的翻译
Published by PVSCoder Sep 16, 2016 (last update: Sep 16, 2016) How to avoid bugs using modern C++
“现代C++”这个术语在C++11发布后变得非常流行。这是什么意思?首先,现代C++是一组模式和习语,旨在消除的缺点美好的“C类”,如此多的C++程序员使用,特别是如果他们开始在C,C++编程11看起来更简洁易懂的方式,这是非常重要的。
C++11增加的功能特性包括:自动类型推断;lambdas表达式;
C++11新增加了auto和decltype关键字。
std::map m;
auto it = m.find(42);
//C++98: std::map::iterator it = m.find(42);
在不影响代码的可读性的情况下,缩短长类型是非常方便的。然而,这些关键字与模板一起变得非常广泛,没有必要用auto和decltype指定返回值的类型。
在64位系统中,下面的代码会出错:
string str = .....;
unsigned n = str.find("ABC");
if (n != string::npos)
在64位系统下,string::npos的值要远大于Unix系统中对于unsigned类型的最大限定值。auto可以解决这个问题,变量n的类型对程序员而言并不重要,我们需要做的就是让它适配string::find所有可能的取值。
string str = .....;
auto n = str.find("ABC");
if (n != string::npos)
使用auto依然会有很多陷阱:
auto n = 1024 * 1024 * 1024 * 5;
char* buf = new char[n];
若本地内存小于5GB,auto无法解决溢出的问题。
auto也无法解决错误循环的问题:
std::vector bigVector;
for (unsigned i = 0; i < bigVector.size(); ++i) // 对于大尺寸数组,这个循环变成了一个无限循环
{ ... }
std::vector bigVector;
for (auto i = 0; i < bigVector.size(); ++i)
{ ... }
在标准C中,将数组作为实参传给函数时,需要意识到传给函数形参的是一个指针,需要用sizeof计算数组的成员的数量。
#define RTL_NUMBER_OF_V1(A) (sizeof(A)/sizeof((A)[0]))
#define _ARRAYSIZE(A) RTL_NUMBER_OF_V1(A)
int GetAllNeighbors( const CCoreDispInfo *pDisp,
int iNeighbors[512] ) {
....
if ( nNeighbors < _ARRAYSIZE( iNeighbors ) )
iNeighbors[nNeighbors++] = pCorner->m_Neighbors[i];
....
}
但是在sizeof (iNeighbors)中,使用sizeof计算的是指针的长度,而不是数组的长度。int iNeighbors[512]在参数中直接说明数组的长度没有发挥任何作用,除了给我们提醒。
使用 C++中的std::array可以避免传统数组的很多问题,它拥有类似vector容器的很多API。
void Foo(std::array array)
{
array.size(); //=> 16
}
enum iscsi_param {
....
ISCSI_PARAM_CONN_PORT,
ISCSI_PARAM_CONN_ADDRESS,
....
};
enum iscsi_host_param {
....
ISCSI_HOST_PARAM_IPADDRESS,
....
};
int iscsi_conn_get_addr_param(....,
enum iscsi_param param, ....)
{
....
switch (param) {
case ISCSI_PARAM_CONN_ADDRESS:
case ISCSI_HOST_PARAM_IPADDRESS:
....
}
return len;
}
上面函数中的参数中,枚举变量来自不同的枚举结构,产生多种不同的情况,是一个隐性错误,但是只会给出warning警告。
在C++11中,您可以并且应该使用enum类:这样的技巧在那里不起作用,并且错误将出现在编译阶段。
enum class ISCSI_PARAM {
....
CONN_PORT,
CONN_ADDRESS,
....
};
enum class ISCSI_HOST {
....
PARAM_IPADDRESS,
....
};
int iscsi_conn_get_addr_param(....,
ISCSI_PARAM param, ....)
{
....
switch (param) {
case ISCSI_PARAM::CONN_ADDRESS:
case ISCSI_HOST::PARAM_IPADDRESS:
....
}
return len;
}
在C++11中被声明弃用,在C++17中被删除。unique_ptr取代了auto_ptr。