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

news2024/7/4 5:52:37

最近在学习使用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贴出来,避免其他小伙伴掉坑里。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

欧拉角,四元数与旋转矩阵

目录 一、欧拉角二、四元数三、旋转矩阵四、Python下欧拉角、四元数和旋转矩阵的相互转换总结 一、欧拉角 对于在三维空间里的一个参考系&#xff0c;任何坐标系的取向&#xff0c;都可以用三个欧拉角(x,y,z)来表现。对于夹角的顺序和标记&#xff0c;夹角的两个轴的指定&…

Baklib分享:做好企业内部知识管理的方法?

企业内部知识管理是一个重要的任务&#xff0c;它涵盖了许多领域&#xff0c;包括知识生成、知识共享、知识保护等。在现代企业中&#xff0c;知识管理被认为是一项战略性的任务&#xff0c;可以为企业带来许多好处&#xff0c;例如提高员工生产力、减少错误和失误、加强员工的…

RabbitMQ 小白教程,从安装到使用

主要内容 AMQP简介 RabbitMQ简介 RabbitMQ原理 Erlang安装 安装RabbitMQ RabbitMQ账户管理 交换器 学习目标 知识点要求AMQP简介掌握RabbmitMQ简介掌握RabbitMQ原理掌握Erlang安装掌握安装RabbitMQ掌握RabbitMQ账户管理掌握交换器掌握 一、 AMQP简介 1 AMQP是什么?…

微信小程序 vue+nodejs高校食堂外卖点餐平台系统rf6md

前端vueelementui, (1) vue引入elementui 1.使用npm安装element-ui npm i element-ui -S 2.在main.js中导入使用vue import element-ui/lib/theme-chalk/index.css //别忘了导入样式 import ElementUI from element-ui Vue.use(ElementUI) 后端&#xff1a;java(springbootss…

蓝牙资讯|智能家居标准Matter 1.1 发布,智能家居产品兼容更丰富

据“CSA 连接标准联盟”官方微信号&#xff0c;Matter 1.1 版本已发布&#xff0c;“1.1 版本带来的更新使设备制造商和开发者上手更容易、产品获取认证更方便&#xff0c;也让产品能更快地交付给用户。该版本还为电池供电设备提供了更大支持&#xff0c;而这类设备涉及多种类型…

VIBRO-METER VM600 MPC4 机械保护卡

4个动态通道和2个转速通道每个动态通道2个处理输出&#xff0c;每个双通道1个处理输出(每个MP C4 2个)&#xff0c;每个转速器通道1个处理输出高度可配置的卡支持机械保护应用所需的所有测量&#xff0c;如相对和/或绝对振动高度集成的卡对(带IOC4T)包括传感器电源、缓冲输出、…

5.2 标准IO:文件的打开、关闭及代码实现

目录 标准IO 文件的打开 标准I/O-fopen-mode参数 ​编辑 标准I/O-fopen-示例 标准I/O-fopen-新建文件权限 标准I/O-处理错误信息 标准I/O-错误信息处理-示例1 标准I/O-错误信息处理-示例2 文件的关闭 标准IO 文件的打开 打开就是占用资源 下列函数可用于打开一个…

四个PCB工程师最头痛的Allegro问题及解答,你一定要看

Allegro是一款功能强大的PCB设计软件&#xff0c;广泛应用在电子设计行业&#xff0c;在使用Allegro过程中&#xff0c;工程师会遇见到多种复杂的技术问题&#xff0c;本文将针对工程师最头痛的Allegro问题进行回答&#xff0c;希望对小伙伴们有所帮助。 1、如何创建新的Allegr…

汽车电子电气架构里的VCU DCU ZCU ECU怎么区分?

文章目录 一、VCU二、DCU三、ECU四、ZCU五、车辆电子电气架构的域架构 一、VCU VCU&#xff08;Vehicle Control Unit&#xff0c;车辆控制单元&#xff09;&#xff1a;VCU是车辆级别的控制单元&#xff0c;负责管理和协调车辆的各个系统和子系统之间的通信和协同工作。它可以…

javaweb实验:JSP+JDBC综合实训__数据库记录的修改、删除

目录 前言实验目的实验内容编程实现后台的用户管理功能 实验原理或流程图实验原理流程图 实验过程AdduserquerAllUserdoAddUser结果展示 实验结论 前言 本实验的目的是让学生掌握使用JSP和JDBC技术对数据库中的记录进行修改和删除的方法。实验内容包括以下几个部分&#xff1a…

STM32单片机蓝牙APP手势语音温控电风扇落地扇人体感应

实践制作DIY- GC0134-蓝牙APP手势语音温控电风扇 一、功能说明&#xff1a; 基于STM32单片机设计-蓝牙APP手势语音温控电风扇 二、功能介绍&#xff1a; 硬件组成&#xff1a;STM32单片机语音识别模块PAJ7620U2手势识别传感器DS18B20温度传感器5V风扇LCD1602显示器红外接…

机器学习算法的基本概念、分类和评价标准,以及一些常用的机器学习算法的原理和特点

机器学习是一门研究如何让计算机从数据中学习和推理的科学。机器学习算法是实现机器学习的具体方法&#xff0c;它们可以根据不同的目标、数据类型和应用场景进行分类和比较。本文将介绍机器学习算法的基本概念、分类和评价标准&#xff0c;以及一些常用的机器学习算法的原理和…

MacBook杀毒软件CleanMyMac X2023

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

复杂软件版本如何使用git工具进行管理

1.需求说明 一个项目&#xff0c;如果长期开发下去&#xff0c;我们会碰到各种各样的客户&#xff0c;然后就会有各种各样的需求。这时候就会出现一个问题&#xff1a;如果我们的代码都是一个项目&#xff0c;客户的主体流程都是一样&#xff0c;但部分客户又有一些特别的定制…

JDK1.8 与 Language Level 8 关系

什么是Java&#xff1f; 是 SUN(Stanford University Network&#xff0c;斯坦福大学网络公司 ) 1995 年推出的一门高级 编程语言。 是一种面向 Internet 的编程语言。Java 一开始富有吸引力是因为 Java 程序可以在 Web 浏览器 中运行。这些 Java 程序被称为 Java 小程序…

六级备考26天|CET-6|仔细阅读|考研英语2023年英语(一)|8:20~10:00

text1 4/5 text2 3/5 text3 2/5 text4 3/5 12/20 目录 text 1 1. 重点词汇 2. 原文 3. 题目 text 1 1. 重点词汇 sympathise / ˈsɪmpəθaɪz / vi.同情&#xff1b;吊唁&#xff1b;共鸣 &#xff08;等于 sympathize&#xff09; ener…

OJ练习第109题——根到叶路径上的不足节点

根到叶路径上的不足节点 力扣链接&#xff1a;1080. 根到叶路径上的不足节点 题目描述 给你二叉树的根节点 root 和一个整数 limit &#xff0c;请你同时删除树中所有 不足节点 &#xff0c;并返回最终二叉树的根节点。 假如通过节点 node 的每种可能的 “根-叶” 路径上值…

KuiperInfer深度学习推理框架-源码阅读和二次开发(3):计算图

前言&#xff1a;KuiperInfer是一个从零实现一个高性能的深度学习推理库&#xff0c;中文教程已经非常完善了。本系列博客主要是自己学习的一点笔记和二次开发的教程&#xff0c;欢迎更多的AI推理爱好者一起来玩。这篇写一下计算图相关的知识点&#xff0c;重点说明ONNX有什么缺…

一口气整理三种不同二维码生成的Java 接入代码

引言 二维码已经成为现代社会中广泛应用的一种工具&#xff0c;它们具有快速、可靠和高容量的信息传递能力。通过扫描二维码&#xff0c;用户可以轻松获取网址、产品信息、支付链接等各种信息。 本文将介绍二维码生成器 API 作为一种工具&#xff0c;并探讨其功能和用法&…

【Linux高级 I/O(4)】异步 IO实例及其优化(全文代码)

异步 I/O 在 I/O 多路复用中&#xff0c;进程通过系统调用 select()或 poll()来主动查询文件描述符上是否可以执行 I/O 操作。 而在异步 I/O 中&#xff0c;当文件描述符上可以执行 I/O 操作时&#xff0c;进程可以请求内核为自己发送一个信号。之后进程就可以执行任何其它…