首页 C++的一些坑
文章
取消

C++的一些坑

这条帖子主要是记录一些在使用C++的时候踩过的坑,不断更新!

编译阶段

编译阶段的坑主要来源于语法,这一阶段的错误基本是个IDE都会带提示,但是针对这部分的问题还是进行针对性记录;

  1. 警告:在有返回值的函数中,控制流程到达函数尾

    缺少return,主要是考虑到如果遇到if条件之外的条件,那就没有返回值了,所以会报警告。

  2. reference to non-static member function must be called

    翻译成中文就是:对非静态成员函数的引用必须被调用;但其实报这个错的场景多种多样,其中一种情况就是之前刷LeetCode遇到的坑;

    Solution类中定义了一个成员函数用来做sort排序函数的谓词,结果出现了这个报错;

    原因其实比较简单,因为sort需要知道这个比较函数的地址才能进行调用,而类的成员函数的调用一定都是隐含了一个this指针来定位到它的位置,但sort显然并非类的成员函数,所以他找不到这个用来比较的成员函数;

    解决方案有两种:

    • 根据报错的提示,在类外部调sort,然后传谓词时,利用类的对象访问,这样是没问题的;
    • 将比较函数定义成static的,static不存在this指针的说法,可以直接调用;

链接阶段

链接阶段遇到的错误真的就需要认真思考了,亲身遇到的第一个例子是关于模板的使用;

  1. 链接阶段出现报错提示:
    1
    2
    3
    
     main.o: In function `main':
     main.cpp:(.text+0x34): undefined reference to `int func<int>(int const&, int const&)'
     collect2: error: ld returned 1 exit status
    

    一般而言,我们在C++中会将头文件的声明和定义分离,这是一种很普遍的做法,也正是这种做法,导致了在使用模板的情形下出现该链接错误提示;

    看个例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
     // add.h直接对函数模板进行了定义
     template <typename T>
     T add(const T &a, const T &b)
     {
         return a + b;
     }
    
     // main.cpp
     #include "add.h"
     int main()
     {
         int i = add(1, 1);
         return 0;
     }
    

    这个例子的头文件包含了函数的声明和定义,这样做当然肯定是没错的,顺利编译链接通过;

    然后我们改一下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
     // add.h只有函数的声明
     template <typename T>
     T add(const T &a, const T &b);
    
     // add.cpp中定义头文件声明的函数
     #include "add.h"
     template <typename T>
     T add(const T &a, const T &b)
     {
         return a + b;
     }
    
     // main.cpp
     #include "add.h"
     int main()
     {
         int i = add(1, 1);
         return 0;
     }
    

    这个时候在链接的过程中则会出现上述的报错;

    因为对于编译器而言,处理函数模板时,他只负责读取与该模板有关的源文件,换句话说,即便main函数将模板特例化为了int,也没人告诉编译器要去编译add.cpp

    那应该怎么解决这个问题呢?改造编译器,重写gcc,要么就是,在头文件中,告诉编译器,我后面要特例化int类型,现在请你去找到针对这个特例化的定义,然后编译他,这个时候就相当于有人告诉编译器要去编译add.cpp了;

    这样是可以解决问题,但是你main函数每调用一种类型就得往头文件加一种类型,太繁琐了,还不如将函数的声明和定义放在一个头文件中;

    所以从这里可以看到,计算机中有很多约定俗成的习惯,但是这些习惯不能奉为教条!

    这样会不会导致一个新的问题:定义放在一个头文件,会不会出现重定义呢?

Tips

本文由作者按照 CC BY 4.0 进行授权

HTTP概述

14-模板与泛型编程