那些年蹚过的坑(c++)

0 关于创建类对象的一些容易出问题的地方(群里 网友 SKY[弃疗]S1xe的原话)

  如果你要调用无参构造函数,那么不要加括号
  如果你要调用有参构造函数,再加上括号
  不然你带括号,没写参数 很可能会被认为函数声明 

1 main中的参数 尽量用英文双引号括起来,否则可能会出现字符串截断的情况(linux gcc 4.4 不加英文引号的话,遇到英文";"会丢弃";"后面的部分)

2 包含ipv6地址结构体(in6_addr)的头文件

        In6addr.h; (Windows Vista and later)

        Ws2tcpip.h (Windows Server 2003 and Windows XP)

3 偶然发现的一个特殊用法

        在for循环里面有switch结构的时候,break; 是结束switch选择分支,而continue; 则是作用于for循环

        for (int i = -1;i<10;++i)

        {

               switch (i)

               {

               case 1:

                    break;

               default:

                    continue;

                }

                cout<<"i= "<<i<<endl;

          }

4 在使用他人提供的动态链接库的时候, 对应的头文件一定要跟动态链接库的头文件完全一致, 否则哪怕只把一个函数变为虚函数, 也会导致在运行时产生莫名其妙的错误

5 mysql 某个用户的Host列为%时, 表示允许任意ip以该用户访问数据库, 但是不包括127.0.0.1. 如果非要这个用户既可以从127.0.0.1,也可以从其他ip访问, 那么应该添加两行记录, 一行写%, 另一行写127.0.0.1

6 inline声明不能用于静态库里面的函数,否则会在编译时找不到函数定义的错误

7 share_ptr 只有执行以下语句后才能指向NULL

  boost::shared_ptr<myobject> client;

  client.reset();

8 小bit有符号整数强制转成大bit无符号

<1>正确步骤: 先转成相同bit的无符号数, 再转成大bit无符号数

  eg: std::int8_t aaa = 239;

    std::uint16_t bbb = (std::uint16_t)(std::uint8_t)aaa; //此时bbb =239

<2>错误步骤: 直接一步强转

  eg: std::int8_t aaa = 239(11101111);

    std::uint16_t bbb = (std::uint16_t)aaa; //此时bbb =65519(11111111 11101111)

9 关于localtime函数

看网上的说法是返回值是一个类型为std::time的静态变量的指针

<1>linux.windows下, 多线程采用以下使用方式 

  tm *p = localtime(&timep);

  时分秒变量的值某些时候也不正确, (┬_┬), 这个是之前输出小时之前没有加"std::setfill('0') << std::setw(2)" 导致时间早于10点时是一位,之后是两位,而审查的时候没有看仔细以为输出错了.  那现在在多线程环境下使用这个函数唯一的缺陷就是时间可能不是很准确

<2>解决办法:

  windows下使用localtime_s, linux下使用localtime_r函数, 这两个函数有两个参数, 可以多线程调用而不出问题, 区别只是参数的顺序不一样

10 一些windows与linux功能相同, 函数名不同的函数

参考自: http://blog.csdn.net/tujiaw/article/details/7871547

  windows:    linux:
  localtime_s   localtime_r
  inet_addr    inet_pton
  GetTickCount    GetTickCount
  Sleep毫秒          sleep秒
  _mkdir             mkdir
  memset            bzero
  _fullpath           realpath

 11 vs2013专属坑

  在vs2013 update5 中 禁止 _CRT_SECURE_NO_WARNINGS error方法.

  (1)这种方法 禁掉的方式很奇葩, 但是很有效.

下面简要说说禁用的方法, 工程中必须使用预编译头文件"stdafx.h", 并且在该文件的#pragma once行之前进行定义宏#define _CRT_SECURE_NO_WARNINGS才有效, 网上针对其他vs版本的方法对vs2013均无效!!!

(2)最近参加的培训, 别人讲了另一种方法, 可能这才是禁止的正确打开方式

  在"解决方案窗口"中的待禁止的项目属性里面, 左侧选择 配置属性-->c/c++-->代码生成, 将右边的"安全检查"修改为禁用安全检查

12 vs2015禁止启动hub server

  工具-->选项-->调试-->禁用调试时启动诊断工具

12 一个类库缺失引发的血案

linux下, 调用第三方so的时候, 莫名提示加载异常

这个有可能是第三方so的依赖库缺失, 因为这种依赖库缺失, 有的时候会提示, 有的时候不会提示, 确认是否是这个问题的一个简单方法就是 "ldd 第三方so", 如果有提示 "not found" 那就是依赖库缺失, 然后装上对应的依赖库就行了

13 输出linux 下gcc的宏定义

  gcc -posix -E -dM - </dev/null  -->输出 c语言的宏定义

  g++ -posix -E -dM - </dev/null -->输出c++语言的宏定义

14 整型常量定义

  八进制:  以"0"开头的数字 eg: 012345

  十进制:  eg: 123542

  十六进制:  以"0x("或者"0X")开头的数字0xab12241324

15 一维数组名与数组元素的指针, 一维数组指针的区别

  (1) 数组名除了存放首地址外,还存放数组元素的个数

  (2) 而数组元素的指针的仅仅存放地址, 最直观的区别就是 用sizeof求字节数的时候, 指针只是指针变量所占的字节数, 而数组名则是元素类型的字节数乘以数组元素的个数 

  (3)一维数组的指针解引用就跟数组名一样了

  eg:  char aaa[10];

    char *p = aaa;

    char (*pa)[10] = &aaa;

    sizeof(aaa)  --> 10

    sizeof(p) -->4或者8

    sizeof(*pa) -->10

16 二进制写入文件的字节序问题

   变量的字节序方式跟内存中的完全一样, 即使用主机字节序写入文件

17 关于函数返回函数对象的问题

  当一个函数返回值是一个对象值类型时, 实际是调用了返回对象对应的类的拷贝构造函数实现的,这里还分两种情况

  <1>当在调用该函数处定义了一个返回值类型的类对象a, 并且以定义并初始化的形式调用该函数时, 实际是调用拷贝构造创建a, 拷贝构造的参数就是函数内的返回值

  <2>当在调用函数处没有定义类对象的时候, 调用函数并且返回的时候, 实际是在调用结束前创建了一个匿名对象, 并且用拷贝构造创建这个匿名对象, 但是这个匿名对象的生存周期在函数调用表达式结束的时候就销毁了, 这个跟<1>中的情形是有区别的.

  class myclass

  {

  public:

    void print();

  };

  myclass fun(const myclass &mc)

  {

    return mc;

  }

  int main(int argc, char **argv)

  {

    myclass aaa;

    fun(aaa); //适用于<1>中的规则

    fun(aaa).print();//适用于<1>中的规则

    myclass bbb = fun(aaa);//适用于<2>中的规则

    return 0;

  }

18 c++ 中关于const int a = 10;的使用问题(这个仅仅是vs系的是这么做的, gcc直接报语法错误)

编译器在把c++源代码翻译成汇编代码的时候, 源代码中使用a的地方直接替换成10, 而不是使用a的地址所对应的值, 这个类似于宏定义

eg:

  const int a = 10;

  int &b = *(int*)&a;

  b = 20;

  std::cout<<a<<" "<<b<<std::endl;

  结果是输出 10 20

19 c++ 用fstream读写文件的问题

  测试环境:

    vs2015

  遇到的问题:

以(std::ios_base::in | std::ios_base::out | std::ios_base::binary)方式打开一个已经存在的文件, 先执行读操作, 然后在当前位置写,发现没有写入

  解决方案及猜测:

在读完写的时候, 调用seekg(tellg()),就可以在当前位置写入数据

从网上翻了15min(没有google的日子真的不好过),有网友提到fstream有两个标示位置的变量, 分别是从basic_istream继承过来的读位置和从basic_ostream继承过来的写位置,以及各有一套读取设置这俩变量的函数(读位置tellg,seekg; 写位置tellp,seekp)

测试发现在vs2015里面从表面上看这四个函数设置的似乎是同一个变量(就是说读位置跟写位置可能是从basic_ios虚继承过来的同一个变量).

根据以上测试结果,推测 "先执行读操作, 然后在当前位置写,发现没有写入"可能的原因是有什么标志变量控制当前的状态, 在调用seekg(或seekp)后, 这个标志变量被重置了, 然后就可以写了

20 CUI程序输出中文

  (1) 使用std::string 保存中文, 然后使用std::cout 就可以输出中文

eg: std::string aaa("中文");

      std::cout<<aaa<<std::endl;

  (2) 使用std::wstring 保存的中文, 相对比较复杂一些,以下是正确的姿势

    eg: include<locale>

      std::wcout.imbue(std::locale("chs"));// 只要在程序所有的输出之前调用一次即可, 不需要每次输出的时候都调用

      std::wstring aaa(L"中文");

      std::wcout<<aaa<<std::endl;

21  std::wstring的构造函数在某些情况下传入空指针会崩溃

22 解决vs2015卡顿问题

https://www.cnblogs.com/17bdw/p/7422688.html

原文地址:https://www.cnblogs.com/talenth/p/5807932.html