ODB 2.4.0 使用延迟指针 lazy_shared_ptr 时遇到的问题

最近在学习使用C++下的ORM库——ODB,来抽象对数据库的CURD,由于C++的ORM实在是太冷门了,ODB除了官方英语文档,几乎找不到其他好用的资料,所以在使用过程中也是遇到很多疑惑,也解决很多问题。近期遇到的一个源码上的bug更是折腾了我很久。写个博客记录一下。

问题描述

举个官方的例子,现在有两张表employees和employers(雇员和雇主),每一个employee行对应一个employer行,模型可以这样设计(省略了一些冗余的代码)

#include <vector>
#include <odb/lazy-ptr.hxx>

#pragma db object 
class Employee  // 雇员
{ 
    ... 

    #pragma db id auto 
    unsigned long id; 

    #pragma db not_null 
    odb::lazy_shared_ptr<Employer> employer; // 一对一关系
}; 


#pragma db object 
class Employer  // 雇主
{ 
    ... 

    #pragma db id auto 
    unsigned long id; 

    #pragma db value_not_null
  	std::vector<lazy_weak_ptr<Employee>> employees_ // 一对多关系
}; 

这里使用lazy_shared_ptr是为了延迟加载,考虑到如果直接使用shared_ptr指针,Employer的数据量比较大的话,每次读取一个employee,就会自动加载对应的employer,非常耗费时间和内存,但是我们又不一定会用到employer。虽然在一对一关系的情况下勉强还能接受,但是如果是一对多关系,那预加载的数据量可能很庞大,吃力不讨好。所以官方提供了lazy-ptr延迟指针帮我们解决这个问题,lazy_shared_ptr指向的对应的employer不会读取employee时立即加载,而是在我们需要时,使用load()方法显式地加载。这种方式更合理。

unsigned long search_id = 52; 
std::shared_ptr<employee> epee(db->load<employee>(search_id)); 
cout << epee->id << endl;
... // 一系列操作之后
epee->employer.load(); // 延迟加载
cout << epee->employer.name << endl;

到这一步以为一切都很顺利,直到编译代码的时候,问题出现了。

/usr/include/odb/lazy-ptr.ixx:1153:10: error: no match for ‘operator=(operand types are ‘std::shared_ptr<Employer>’ and ‘odb::object_traits<Employer>::pointer_type’ {aka ‘Employer*’})
 1153 |       p_ = i_.template load<T> (true); // Reset id.
      |       ~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/c++/10/memory:84,
                 from driver.cxx:4:
/usr/include/c++/10/bits/shared_ptr.h:358:19: note: candidate: ‘std::shared_ptr<_Tp>& std::shared_ptr<_Tp>::operator=(const std::shared_ptr<_Tp>&) [with _Tp = Employer]358 |       shared_ptr& operator=(const shared_ptr&) noexcept = default;
      |                   ^~~~~~~~
/usr/include/c++/10/bits/shared_ptr.h:358:29: note:   no known conversion for argument 1 from ‘odb::object_traits<Employer>::pointer_type’ {aka ‘Employer*’} to ‘const std::shared_ptr<Employer>&358 |       shared_ptr& operator=(const shared_ptr&) noexcept = default;
      |                             ^~~~~~~~~~~~~~~~~
/usr/include/c++/10/bits/shared_ptr.h:362:2: note: candidate: ‘template<class _Yp> std::shared_ptr<_Tp>::_Assignable<const std::shared_ptr<_Yp>&> std::shared_ptr<_Tp>::operator=(const std::shared_ptr<_Yp>&) [with _Yp = _Yp; _Tp = Article]362 |  operator=(const shared_ptr<_Yp>& __r) noexcept
      |  ^~~~~~~~ 

出现问题

解决问题

看错误提示,应该是shared_ptr的问题,我一开始一头雾水,去网上查了好多资料,也没人提出同样的问题(想不到ODB真就这么冷门)。查资料查了半天无果,决定从源码入手解决问题。
问题出在源码中/usr/include/odb/lazy-ptr.ixx的第1153行代码

  template <class T>
  inline std::shared_ptr<T> lazy_shared_ptr<T>::
  load () const
  {
    if (!p_ && i_)
      p_ = i_.template load<T> (true); // Reset id. 就是这一行代码

    return p_;
  }

可以看出p_的类型应该是std::shared_ptr<T>,检测i_.template load<T> (true);发现它的返回值是T*指针类型,输出的错误告诉我们找不到将T*指针类型赋值给std::shared_ptr<T>的操作。很明显,不能将一个原始指针直接赋值给一个智能指针(这个可以在各种博客和教程上查到),所以程序编译不通过,正确的做法应该是使用reset()方法,修改代码如下

  template <class T>
  inline std::shared_ptr<T> lazy_shared_ptr<T>::
  load () const
  {
    if (!p_ && i_)
      //p_ = i_.template load<T> (true); // Reset id.
      p_.reset(i_.template load<T> (true)); // Reset id.

    return p_;
  }

重新编译代码,编译成功,问题解决!
/usr/include/odb/lazy-ptr.ixx第1551行也有同样的问题,可以一起改了。

总结

由于我使用的版本是2.4.0,是2015年发布的版本,当时C++11可能还有许多问题没有完善,导致这个版本也有对应的bug(比如我现在遇到的这个bug,不知道是不是因为当时shared_ptr还没有规定不能直接被原生指针赋值的问题),我看到现在2.5.0已经在测试了(2022年的),相信这里提到的问题应该能在2.5.0版本得到解决。考虑到2.5.0版本还没正式发布,我还是把2.4.0版本可能会遇到的这个bug贴出来,避免其他小伙伴掉坑里。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/22077.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

推荐系统系列之推荐系统概览(下)

在推荐系统概览的第一讲中&#xff0c;我们介绍了推荐系统的常见概念&#xff0c;常用的评价指标以及首页推荐场景的通用召回策略。本文我们将继续介绍推荐系统概览的其余内容&#xff0c;包括详情页推荐场景中的通用召回策略&#xff0c;排序阶段常用的排序模型&#xff0c;推…

Keil Debug 逻辑分析仪使用

Keil Debug 逻辑分析仪使用 基础配置 更改对应的bebug窗口参数 两边的 Dialog DLL 更改为&#xff1a;DARMSTM.DLL两边的 Parameter &#xff08;这里的根据单片机型号更改&#xff09;更改为&#xff1a;-pSTM32F103VE 选择左边的 Use Simulator 选项。 打开Debug和其中的逻…

数据全生命周期管理

数据存储 时代"海纳百川&#xff0c;有容乃大"意味结构化、半结构和非结构化多样化的海量的 &#xff0c;也意味着批数据和流数据多种数据形式的存储和计算。面对不同数据结构、数据形式、时效性与性能要求和存储与计算成本等因素考虑&#xff0c;应该使用适合的存储…

iptables防火墙(二)

iptables防火墙&#xff08;二&#xff09; 一、SNAT策略1、SNAT策略简述2、配置实验 二、DNAT策略1、DNAT策略简述2、配置实验 三、Linux抓包工具tcpdump四、防火墙规则保存 一、SNAT策略 1、SNAT策略简述 SNAT策略就是将从内网传给外网的数据包的源IP由私网IP转换成公网IP&…

四川省信创联盟2023年第一次理事会顺利召开,MIAOYUN荣获“信创企业优秀奖”!

5月18日&#xff0c;四川省技术创新促进会信创工委会&#xff08;四川省信创产业联盟&#xff09;在成都市高新区新川科技园成功召开《2023年第一次理事单位&#xff08;扩大&#xff09;会议》&#xff0c;四川省技术创新促进会专家组杜纯文副组长、四川省技术创新促进会任渝英…

EasyRecovery16适用于Windows和Mac的专业硬盘恢复软件

无论你对数据恢复了解多少&#xff0c; 我们将为您处理所有复杂的流程并简化恢复!适用于Windows和Mac的 专业硬盘恢复软件 硬盘数据无法保证绝对安全。有时会发生数据丢失&#xff0c;需要使用硬盘恢复工具。支持恢复不同存储介质数据&#xff1a;硬盘、光盘、U盘/移动硬盘、数…

AC规则-1

本文主要参考规范 GPD_Secure Element Access Control_vxxx.pdf OMA 架构 基本定义 GP(GlobalPlatform)定义了一套允许各应用提供方独立且安全地管理其在SE上的应用的安全框架&#xff0c;而AC(Access Control)&#xff0c;顾名思义&#xff0c;是对外部应用进行SE上应用访问…

网络知识点之-动态路由

动态路由是指路由器能够自动地建立自己的路由表&#xff0c;并且能够根据实际情况的变化适时地进行调整。 中文名&#xff1a;动态路由外文名&#xff1a;dynamic routing 简述 动态路由是与静态路由相对的一个概念&#xff0c;指路由器能够根据路由器之间的交换的特定路由信息…

【Python redis】零基础也能轻松掌握的学习路线与参考资料

Python redis是一种非常流行的缓存数据库&#xff0c;对于Python Web应用程序开发非常有用&#xff0c;能快速地处理大量的数据请求。Python redis的学习路线需要对Python语言有深刻的理解&#xff0c;并了解使用redis的API。在掌握了Python redis的基本知识后&#xff0c;就可…

Java设计模式-策略模式

简介 在软件开发中&#xff0c;设计模式是为了解决常见问题而提供的一套可重用的解决方案。策略模式&#xff08;Strategy Pattern&#xff09;是其中一种常见的设计模式&#xff0c;它属于行为型模式。该模式的核心思想是将不同的算法封装成独立的策略类&#xff0c;使得它们…

【halcon资料】取出区域的轮廓上所有转折点

一、说明 在区域运算的时候&#xff0c;有时候需要用图形的顶点来描述&#xff0c;比如&#xff0c;两个图中对象需要对齐&#xff0c;或者仿射变换&#xff0c;于是特征点是需要提取的。本文给出一个提取顶点的示例。 二、算子 1.1 get_region_polygon算子 &#xff08;1&a…

高级树结构

二叉排序树 左子树中所有结点的值&#xff0c;均小于其根结点的值。 右子树中所有结点的值&#xff0c;均大于其根结点的值。 二叉搜索树的子树也是二叉搜索树。 注意&#xff1a; 1.二叉查找树不能插入重复元素 2.中序遍历是一个递增的数列 3.高度越小查询效率越高 二叉排序…

设备采购信息管理系统

系列文章 任务14 设备采购信息管理系统 文章目录 系列文章一、实践目的与要求1、目的2、要求 二、课题任务三、总体设计1.存储结构及数据类型定义2.程序结构3.所实现的功能函数4、程序流程图 四、小组成员及分工五、 测试界面展示添加采购信息按编号查找采购信息按设备编号查找…

macOS Ventura 13.5beta (22G5027e)发布

系统介绍 黑果魏叔 5 月 20 日消息&#xff0c;苹果今日向 Mac 电脑用户推送了 macOS 13.5 开发者预览版 Beta 更新&#xff08;内部版本号&#xff1a;22G5027e&#xff09;&#xff0c;本次更新距离上次发布隔了 17 天。 macOS Ventura 带来了台前调度、连续互通相机、Face…

【SpringBoot】SpringBoot 纯后端项目如何自定义异常页面(Whitelabel Error Page)

文章目录 背景安排方案步骤 验证 背景 一个短链服务&#xff0c;业务将长链接给我&#xff0c;我转换成短地址&#xff0c;用户访问短地址时&#xff0c;我再做redirect&#xff1b;没有前端&#xff0c;纯后端项目短链会有过期时间&#xff0c;过期后将返回错误信息某一天一个…

本地电脑做服务器搭建私人音乐网站ThinkMusic + cpolar内网穿透

文章目录 1. 前言2. 本地网页搭建2.1 环境使用2.2 支持组建选择 3. 网页安装3. 本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4. 公网访问测试5. 结语 转发自CSDN lisacpolar的文章&#xff1a;ThinkMusic源码搭建音乐网站&#xff0c;并实现公网访问 1. 前言 在我们的日…

Redis 概述

1. NoSQL 数据库简介 技术发展: 技术的分类 1、解决功能性的问题&#xff1a; Java、 Jsp、 RDBMS、 Tomcat、 HTML、 Linux、 JDBC、 SVN2、解决扩展性的问题&#xff1a; Struts、 Spring、 SpringMVC、 Hibernate、 Mybatis3、解决性能的问题&#xff1a; NoSQL、 Java 线…

MacBook杀毒软件CleanMyMac X2023

Mac 上也广泛存在恶意软件&#xff0c;并且能够突破系统自身的防护&#xff0c;通过渠道传播到电脑上&#xff0c;威胁大家的数据安全和窃取个人信息&#xff01;所以&#xff0c;MacBook杀毒软件还是很有必要安装的。 始于颜值&#xff0c;忠于实力。CleanMyMac X是我用过UI风…

Java 与排序算法(3):插入排序

一、插入排序 插入排序&#xff08;Insertion Sort&#xff09;是一种简单直观的排序算法&#xff0c;它的基本思想是将待排序序列分为已排序区间和未排序区间&#xff0c;然后每次从未排序区间取出一个元素&#xff0c;将其插入到已排序区间的合适位置中&#xff0c;使得插入…

【Linux0.11代码分析】09 之 ELF可执行程序02 - Section Headers解析

【Linux0.11代码分析】09 之 ELF可执行程序02 - Section Headers解析 一、ELF概述二、ELF的组成结构2.1 ELF header&#xff1a;解析出 section headers 含31个section节和 program headers 含13个segment段2.2 Section Headers&#xff1a;获取当前程序的31个section节区信息2…