C++-踩坑

gcc/g++的编译链接原理及注意事项

LINUX下默认搜索头文件及库文件的路径

编译连接

多个文件编译在linux下编译,下面有三个文件,分别是1.cpp 和 2.cpp 和myhead.h 文件。

1.cpp

1
2
3
4
5
6
7
8
9
#include <iostream>
#include "myhead.h"
using namespace std;

int main(){
print();
cout<<"yes !"<<endl;
return 0;
}

2.cpp

1
2
3
4
5
6
7
8
9

#include <iostream>
#include "myhead.h"
using namespace std;

void print(){
std::cout<<" print "<<std::endl;
cout<<
}

myhead.h

1
2
3
4
5

#ifndef __myhead_h
#define __myhead_h
void print();
#endif

假如他们都在一个目录下面,那么编译流程:

1
2
g++ -c 2.cpp             #将2.cpp 编译成2.o 文件
g++ 1.cpp -o a.out 2.o #多个文件一起链接

or

1
2
3
g++ -c 2.cpp
g++ -c 1.cpp
g++ 1.o 2.o -o test

重写C++中异常类的what方法

待补充完善:错误原因以及为什么这么修改

坑源

在实现项目ZeroTensor的专属异常类时,需要实现exception类的what方法。

出现问题及解决办法

首先需要看一下exception基类中关于what方法的原始定义:

1
2


下面是正确的重写方式

1
const char *what() const throw() override { return error_msg_.c_str(); }

如果去掉throw() , 则会报错:

1
2
looser throw specifier forvirtual const char* zerotensor::ZerotensorError::what() const
const char *what() const override { return error_msg_.c_str(); }

如果将char * 改为 string,则会报错:

1
2
error: ‘const string zerotensor::ZerotensorError::what() const’ cannot be overloaded
const string what() const throw() override { return error_msg_; }

声明模板类对象,报错“undefined reference to”

坑源

实现ZeroTensor项目中的Shape3D类时,为了可以处理多种类型的数据(int,double等),需要使用模板类

出现问题和解决办法

在实现的时候将模板类的声明和定义写在的不同位置,编译时报错:

1
undefined reference to XXXX

这是因为模板类并不是普通的类和成员函数!它们只是说明了如何生成类和成员函数定义。因此,不能将模板成员函数放在独立的实现文件中。

由于模板不是函数,因此它们不能单独编译。模板必须与特定的模板实例化请求一起使用。为此,最简单的方法是将所有模板信息放在一个头文件中,并在要使用这些模板的文件中包含该头文件!

还有另一种解决办法就是在stack.h文件的末尾加上#include stack.cpp,并在stack.cpp文件中去掉对应的包含语句。

string.substr

坑源: leetcode, 第140题, Word Brak II

s.substr(word.size()) 可以通过, 但是s.substr(0, word.size()) 报错 runtime error.

原因:

1
basic_string substr(size_type pos=0, size_type count=npos) const;

当只指定一个参数时, 该参数表示的是 pos 的位置, 而 count 则默认会是字符串中剩余字符的数量.

如果 pos 的值大于字符串的size, 则会报运行时错误(runtime error).

vector数据的内存分配问题

首先,要知道,程序所拥有的栈资源是及其有限的(Linux下用ulimit -a或者ulimit -s可查当前栈的大小。 因此在写程序时,绝对不能肆意使用占空间,否则就会报出Segmentation fault

在用vector实现三维数据时,以下的代码就会产生段错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <vector>
using namespace std;

int main() {

int HEIGHT=2,WIDTH=3,DEPTH=5;
// construct array3D[HEIGHT][WIDTH][DEPTH]
vector<vector<vector<double> > > array3D;

array3D.resize(HEIGHT);
for (int i = 0; i < HEIGHT; ++i) {
array3D[i].resize(WIDTH);
for (int j = 0; j < WIDTH; ++j)
array3D[i][j].resize(DEPTH);
}

return 0;
}

以上出现段错误的原因在于申请了过多的vecotr,导致占空间不够用,从而出现段错误,现在来看以下vector在内存中具体是如何存储的,首先看一下以下三种方式的声明:

1
2
3
4

std::vector<T> vec;
std::vector<T>* Vec = new std::vector<T>();
std::vector<T*> vec;

假设T是一个类型或者一个定义好的类,则以上三种情况的内存分配情况如下:

  • 对于std::vector<T> vecvec在栈上(stack),而其中的元素T保存在堆上(heap);
  • 对于std::vector<T>* Vec = new std::vector<T>()vec和其中的元素T都保存在堆上;
  • 对于std::vector<T*> vecvec在栈上(stack),而其中的元素T保存在堆上(heap);和第一种情况类似。

存储在栈上的元素,往往无需手动管理内存空间,通常会自动释放,而在堆上的空间,则需要手动管理。

在实现项目ZeroTensor的专属异常类时,需要实现exception类的what方法。

出现问题及解决办法

首先需要看一下exception基类中关于what方法的原始定义:

1
2


下面是正确的重写方式

1
const char *what() const throw() override { return error_msg_.c_str(); }

如果去掉throw() , 则会报错:

1
2
looser throw specifier forvirtual const char* zerotensor::ZerotensorError::what() const
const char *what() const override { return error_msg_.c_str(); }

如果将char * 改为 string,则会报错:

1
2
error: ‘const string zerotensor::ZerotensorError::what() const’ cannot be overloaded
const string what() const throw() override { return error_msg_; }