在我的音视频项目中使用了模版特化的RAII,
问题描述
在对音视频上下文进行封装的时候遇到了重定义问题(即模版特化导致多重定义链接错误),代码如下(AVGuard.h):
//模版特化的安全退出函数
//AVFormateContext
template <>
AVGuard<AVFormatContext>::AVGuard(){
m_ctx = avformat_alloc_context();
}
template <>
AVGuard<AVFormatContext>::~AVGuard(){
if (m_ctx) {
avformat_close_input(&m_ctx);
avformat_free_context(m_ctx);
}
m_ctx = nullptr;
}
//AVPacket
template <>
AVGuard<AVPacket>::AVGuard(){
m_ctx = av_packet_alloc();
}
template <>
AVGuard<AVPacket>::~AVGuard(){
AVPacket *m_avpacket = m_ctx;
if (m_avpacket) {
av_packet_free(&m_avpacket);
m_avpacket = nullptr;
}
}
但是如果我在AVGuard.cpp
下包含这个头文件,则AVGuard.cpp、main.cpp包含多个相同函数的定义,链接时会出现重定义问题,如下:
产生原因分析
模版的原理为当编译器读到AVGuard时,编译器会创建一个新类。
模版定义(参数检查) --> 模版实例化(参数推导和替换)
全特化就是限定模版实现的具体类型。
当一个头文件中既有未特化的实例化类和特化的实例化类时,就出现了重复定义。
解决方法
- 使用内联(可以在多个文件中调用)声明特例化模版,但是一些函数的实现可能不支持内联
不太优雅 - 定义普通同名函数,通过重载调用非模版函数
太麻烦 - 使用static定义(文件域)
构造函数不能声明为static - 把特化从头文件中拿出,放在实现文件中
cmd + c/v 完成,编译成功
//模版特化的安全退出函数
//AVFormateContext
template <>
AVGuard<AVFormatContext>::AVGuard(){
av_log(NULL, AV_LOG_INFO, "AVGuard:AVFormatContext Definition Construction\n");
m_ctx = avformat_alloc_context();
}
template <>
AVGuard<AVFormatContext>::~AVGuard(){
if (m_ctx) {
av_log(NULL, AV_LOG_INFO, "AVGuard:AVFormatContext Definition Deconstruction\n");
avformat_close_input(&m_ctx);
avformat_free_context(m_ctx);
}
m_ctx = nullptr;
}
打印日志:
测试成功!