c++编程经验及常见编译错误小结

说明

本文主要记录了我在开发过程中遇到的问题,包括编译错误、调试失败等的总结。

我会给出问题的原因及解决方法,并尽可能列出可以提供详细信息的相关链接。

可以在本页搜索关键字获取相关内容。

注:发生问题的原因可能不止一种,这里的解决方法并非唯一和最优,欢迎探讨。此文会持续更新。

环境

gcc及系统版本:

% gcc --version
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

% uname -a
Linux 4.4.0-94-generic #117-Ubuntu SMP Tue Aug 29 08:13:56 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
编码经验

  • 使用c11的for(auto x : vec)循环修改元素时,容器中实际值未改变

    • 原因:该循环以拷贝值的方式访问容器,修改的是临时变量的值,原值未改变
    • 修改:使用 for(auto &x : vec)即可访问修改原始值。当不需要修改原始内容时,建议使用 for (auto const &x : vec),该方式直接访问原始内容,省略拷贝过程
  • 调试时打印输出函数名、文件名、行号等信息

__FUNCTION__, __FILE__, __LINE__
  • 有没有跨平台的sleep函数
// c11
#include <thread>
#include <chrono>
std::this_thread::sleep_for(std::chrono::seconds(1));
  • boost asio async_accept没有响应

    • 原因:未启动io_service或者启动位置不对
    • 修改:在调用异步操作之后启动ios.run()(注意在一个线程内启动,否则会阻塞)
  • boost asio中已经post的任务未执行就退出了

    • 原因:post后执行了ios.stop(),导致工作线程退出,任务不再执行
    • 修改:使用boost::shared_ptr<boost::asio::io_service::work> m_work绑定ios,执行m_work.reset()会等待任务执行完成后退出
  • boost asio中,使用 m_socket.is_open();总是返回true

  • g++的编译选项中,-std=c++0x 和 -std=c++11 应该选择哪一个,有什么区别?

    • 如果编译器支持,应该选用 -std=c++11

    • 仅对于不支持-std = c ++ 11的较旧的编译器版本,才需要旧的-std = c ++ 0x。0x可能代表了03、08等发布的尚不稳定的特性,C ++ 11标准正式发布之前更改了一些细节,以适应该标准不断变化的工作草案

    • 关于兼容性:可能存在差异和不兼容性,但是这些不仅仅与-std = c ++ 0x的使用有关,还与编译器的特定版本有关。 当编译器同时支持两者时,它们应该相同

    • What is the difference between -std=c++0x and -std=c++11

  • 经常会需要删除map中的某个迭代器,有没有好用的方法?

    • 当需要删除map中指定迭代器时,一般都是先遍历map,找到后再删除。在for循环中使用iter++,再循环体中mymap.erase(iter)的错误做法应该避免
    • 注意到迭代器在删除后失效,for循环不再会退出后,下面是行之有效的代码:
std::map<K, V>::iterator itr = myMap.begin();
while (itr != myMap.end()) {
    if (ShouldDelete(*itr)) {
    	 std::map<K, V>::iterator toErase = itr;
       ++itr;
       myMap.erase(toErase);
       
       // 下面这一行与上面三行等效
       //myMap.erase(itr++);  // <--- Note the post-increment!
    } else {
       ++itr;
    }
}

// 下面适用于c11
std::map<K, V>::iterator itr = myMap.begin();
while (itr != myMap.end()) {
    if (ShouldDelete(*itr)) {
       itr = myMap.erase(itr); // erase会返回指向下一个元素的迭代器
    } else {
       ++itr;
    }
}
  • 新建对象时的两种方式:new Foo() vs new Foo

    • 两种方式都可以创建对象,但是否带小括号会影响创建对象的具体结果:是否初始化。初始化的方式又取决于编译器的版本及该对象是否是POD类型。
    • POD类型(Plain Old Data),简单的解释就是没有构造、析构函数且没有虚函数的类,如 struct A { int m; }; // POD
    • new Foo(): 显式构造,new Foo:是否调用构造函数不重要。对于自定义构造函数的类来说,没有区别。
    • 具体区别如下Do the parentheses after the type name make a difference with new?
struct A { int m; }; // POD
struct B { ~B(); int m; }; // non-POD, compiler generated default ctor
struct C { C() : m() {}; ~C(); int m; }; // non-POD, default-initialising m

// c++98
// new A: 未确定的值
// new A(): 0初始化

// new B: 默认构造,m未初始化
// new B(): 默认构造,m未初始化

// new C: 默认构造,0初始化
// new C(): 默认构造,0初始化

// c++03
// new A: 未确定的值
// new A(): 值初始化,因为是POD,所以是0初始化

// new B: 默认初始化,默认构造,m未初始化
// new B(): 值初始化,因为是默认构造,0初始化

// new C: 默认初始化,调用默认构造
// new C(): 值初始化,调用默认构造
  • 如何把std::unique_ptr放入map?

    • std::unique_ptr 是只移型别,不能复制,移动后源指针会被置空
    • 可以使用 myMap.insert(std::make_pair(0, std::unique_ptr<Class1>(new Class1()))); 或者 myMap[0] = std::unique_ptr<Class1>(new Class1());,也可以 myMap.insert(std::make_pair(0,std::move(up)));
    • 如果支持c14,建议使用 myMap[0] = std::make_unique<Class1>();
  • 如何只使用c11使线程进入永久休眠?

    • 经常需要在主线程中休眠,以等待其他线程处理完成
    • 有多种方式可以达到这个目的,如while(true) usleep(1), while(1) pause()等,其实sleep方式也会耗费cpu时间(极短)
    • 也可以使用一个永远不会返回true的信号量,如:
// 可以达到目的,但非常无聊,且毫无理由如此做
std::condition_variable cv;
std::mutex m;
std::unique_lock<std::mutex> lock(m);
cv.wait(lock, []{return false;});
  • 也可以使用一个永远不会置位的期值:std::promise<void>().get_future().wait();,同样没有理由这样做
  • 好了,较优雅的方式来了:std::this_thread::sleep_until(std::chrono::system_clock::now() + std::chrono::hours(std::numeric_limits<int>::max())); // sleep到天荒地老
  • 参考:https://stackoverflow.com/questions/36711131/how-to-sleep-forever-only-using-c11
编译错误

  • invalid new-expression of abstract class type

    • 原因:实例化了一个虚类,该类至少有一个成员函数是虚的,未实现。

    • 修改:

    • [] 实现该成员函数

    • [] 从该类派生一个类,实现各成员,并使用该派生类

    • invalid new-expression of abstract class type

  • ‘[Class name]’ does not name a type in C++

  • error: ‘shared_ptr’ in namespace ‘std’ does not name a template type

    • 原因:没有包含头文件
    • 修改:
    • 如果使用 std::shared_ptr,使用 #include <memory>
    • 如果使用 boost::shared_ptr,使用 #include <boost/shared_ptr.hpp>
  • error: declaration of ‘auto data’ shadows a parameter

    • 原因:该行代码中的变量data已经在之前定义过,它覆盖了参数,也就是说该变量与函数参数同名
    • 修改:修改该变量名不与参数同名即可
  • error: invalid use of incomplete type 'class ClientMgrBase

    • 原因:使用了不完整的类型的类,仅前向声明了一个类,而未见完整定义时就使用该类的指针
    • 修改:把类的声明放在h中,在cpp中使用该类的指针
  • error: jump to case label [-fpermissive]

    • 原因:在某个case中定义了局部变量,且之后仍有其他case语句,所以该变量的作用域一直有效。这样可能会导致异常或崩溃
    • 修改:在每个case后使用作用域限定符{},或者不要在case中定义局部变量
  • error: tr1::bad_weak_ptr

    • 原因:把shared_form_this()用在了一个没有shared_ptr指向的对象上,enable_share_from_this在实现时使用了一个对象的weak_ptr,而这个weak_ptr需要对象的shared_ptr进行初始化。由于此时对象尚未构造完成,所以会抛出std::bad_weak_ptr的异常
    • 修改:使用 boost::shared_ptr<A>(this)创建对象A的智能指针作为参数,或者在Init函数中完成类似指针的使用
    • enable_shared_from_this - empty internal weak pointer?
  • initial value of reference to non-const must be an lvalue

  • Undefined reference to ‘dlsym’

    • 原因:程序中使用了 dlsym 系列函数,如进行了动态库的动态加载等,而没有链接该库
    • 修改:g++ demo.c -ldl,如果还是不行,尝试使用 -lstdc++ -Wl,--no-as-needed -ldl
    • Undefined reference to ‘dlsym’
  • ‘memset’ was not declared in this scope

    • 原因:没有包含相关的头文件
    • 修改:#include <cstring>
  • 使用类的静态成员变量时,undefined reference to `A::m_a’

    • 原因:只在头文件中声明了静态成员变量,未定义该变量,所以未为该变量分配存储空间(注意,如果是非静态的,会在实例化时分配内存,不会报错)
    • 修改:在使用之前定义该成员变量即可。在cpp中,使用它之前定义,如:int A::m_a = 0;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值