变量的声明VS定义
声明是向编译器介绍变量,它的名字、类型,可包括初值。
定义则使编译器确定变量的内存空间。
变量的声明与定义往往是同时的,
int a;
若只想声明变量,但不分配内存,extern
extern int a;
函数与变量类似。只声明不定义,如下
int add(int, int);
OpenCV
-
Rect
参数顺序 x y w h
Rect_ (_Tp _x, _Tp _y, _Tp _width, _Tp _height)
-
Mask
将logo图片贴在大图上
// 原图
cv::Mat pic;
cv::Mat logo = ...;
// 确保Mask为CV_8UC1
cv::Mat mask = ...;
logo.copyTo(pic(cv::Rect(1,3,1920,1080)), mask);
auto mask_ = cv::Mat::zeros(imGray.size(), CV_8UC1);
cv::Rect rect(0, 0, 1920, 1020);
mask_(rect).setTo(255);
- cv::Mat::reshape
cv::Mat::reshape(int channels, int rows)
,参数分别为通道数,行数,
注意与python numpy的reshape不同。
Eigen
NColsBlockXpr<N>::Type middleCols(Index startCol, Index n = N)
返回矩阵中的一块,包含n列。- Ax=b
x_ = H_.ldlt().solve(Jres_);
- 块操作
Matrix4d T;
Matrix3d R;
R = T.block<3,3>(0,0);
Vector3d p;
Vector2d px=p.head<2>()/p[3];
//第i个元素开始的n个元素
p.segment<i>(n);
- skew
- 四元数
Eigen::Quaterniond = Eigen::Matrix3d()*Eigen::Quaterniond()
LLT
MAP
C++ 内存管理
allocator
分配未构造的内存。
//可以分配std::string的对象
std::allocator<std::string> alloc;
//分配n个未初始化的string
auto const p = alloc.allocate(n);
//q指向最后构造的元素之后的位置
auto q = p;
alloc.construct(q++);
alloc.construct(q++, 10, 'c');
alloc.construct(q++, “hello,world”);
while(q != p){alloc.destroy(--q);
}
模板
template <typename T, int a, int b> using Matrix = Eigen::Matrix<T, a, b>;Matrix<double, 2, 6> frame_jac;
静态成员
- 静态成员为类的全部对象共享,类似于全局变量。例如,银行账户类需要与利率关联,我们期望利率与类关联,而非与类的各个对象关联,从实现效率的角度看,没必要每个对象都存储利率信息,更重要的,一旦利率浮动,期望所有对象都能使用新值。
- 在类的外部定义和初始化每个静态成员,只有常值变量const 或 constexpr 静态变量可以在声明时初始化。
- 静态数据成员定义在任何函数之外,一直存在于程序的整个生命周期中。
- If the member is used only in contexts where the compiler can substitute the member’s value, then an initialized const or constexpr static need not be separately defined. However, if we use the member in a context in which the value
cannot be substituted, then there must be a definition for that member. 除只用于在编译时替换静态变量的值外,需要在类外对静态成员变量初始化,以保证编译正确。 - 静态成员函数内部不能引入非静态成员变量,非静态成员可以使用静态成员。
static constexpr
声明
class Account {
public:
void calculate() { amount += amount * interestRate; }
static double rate() { return interestRate; }
static void rate(double);
private:
std::string owner;
double amount;
static double interestRate;
static double initRate();
};
拷贝控制的3/5法则
3种方法控制类的拷贝操作,复制构造、复制赋值运算符、析构函数;新标准增加了移动构造、移动赋值。
- 需要(自定义)析构函数的类也需要拷贝控制,复制构造函数、赋值运算符号。
- 需要复制操作的类也需要赋值操作,反之亦然,不需要析构函数。
拷贝控制示例
C++ Primer中簿记操作的例子,设计两个类,可用于邮件处理应用。
Message与Folder类
- Message保存Folder指针的set;Folder保存Message指针的set。
- 复制构造一个Message时,副本即新创建的对象和原对象是两个不同的对象,但都在相同的Folder中,即需要拷贝Folder指针的集合,在包含此消息的Folder中都添加新创建的Message指针。
- 将一个Message对象赋值给另一个Message时,左侧Message的消息内容被右侧的替换;从所有包含左侧Message的Folder中删除该Message指针;并将该Message指针添加到右侧Message的Folder指针集合。
- 销毁Message时,从包含此Message的所有Folder中删除此Message指针。
总结,析构函数和复制赋值函数中都有从包含原Message的所有Folder中删除该Message指针;复制构造函数和复制赋值函数都包含新Message指针添加到Folder中。
模拟标准库中的vector
时刻
- C语言
#include <ctime>
time_t t_cur=time(0);
//...
time_t t_now=time(0);
//运行时间
double dt=difftime(ts_now, ts_cur);
- C++
#include <chrono>std::chrono::time_point<std::chrono::system_clock> now;
auto start = std::chrono::steady_clock::now();
//...
auto end = std::chrono::steady_clock::now();
std::chrono::duration<double> diff = end -start;
double time = diff.count();
工程问题解决
/usr/bin/ld: warning: libpng12.so.0, needed by xxx/libgdal.so.20, not found (try using -rpath or -rpath-link)
解决方法sudo apt install libpng12-0
error: ‘function’ is not a member of ‘std’
指明C++11特性
g++ test.cpp -std=c++0x
TypeError: 'builtin_function_or_method' object is not iterable
问题原因:调用成员函数未加()
-
启用core dump功能,并设置目录和命名规则
/proc/sys/kernel/core_uses_pid可以控制产生的core文件的文件名中是否添加pid作为扩展,如果添加则文件内容为1,否则为0
/proc/sys/kernel/core_pattern可以设置格式化的core文件保存位置或文件名,比如原来文件内容是core-%e
echo “/corefile/core-%e-%p-%t” > /proc/sys/kernel/core_pattern -
类的静态成员未初始化,导致
undefined references to
ulimit -c unlimited
sudo bash -c 'echo /tmp/core.%e.%p > /proc/sys/kernel/core_pattern'
cat /proc/sys/kernel/core_pattern
because the following virtual functions are pure within
定义ceres::CostFunction
的子类,重定义虚函数时,缺少右边的const导致error
virtual bool Evaluate(double const *const *parameters, double *residuals,
double **jacobians) const
json
for (json::const_iterator it = json_in.begin(); it != json_in.end(); ++it) {auto k = it.key();auto v = it.value();}
json可以支持“大”数组。
std::map<std::string, std::string> a;a.insert(std::pair<std::string, std::string>("3", "zhang"));std::map<std::string, std::string> b;b.insert(std::pair<std::string, std::string>("4", "li"));std::vector<std::map<std::string, std::string>> vf{a,b};json j(vf);std::ofstream ofs("./test_new_json.json");ofs << j;ofs.close();
编程体会
- 明确目标,把目标分阶段,保证可以实现,循序渐进
- 谋定后动:先写出要实现的功能函数,再具体实现
- 自上而下设计,从最终目标开始,从总到分,从抽象到具体实现,先写出类、函数功能再具体实现
- 广泛深入调研参考