面试经验:丢失更新(第一类&第二类)

本文通过银行转账和取款的实例,详细解析了第一类和第二类丢失更新问题,展示了当两个事务交错执行时,如何可能导致数据不一致的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第一类丢失更新 

    A事务撤销时,把已经提交的B事务的更新数据覆盖了。这种错误可能造成很严重的问题,通过下面的账户取款转账就可以看出来:

时间

取款事务A

转账事务B

T1

开始事务

 

T2

 

开始事务

T3

查询账户余额为1000元    

 

T4

 

查询账户余额为1000元

T5

 

汇入100元把余额改为1100元

T6

 

提交事务

T7

取出100元把余额改为900元

 

T8

撤销事务

 

T9

余额恢复为1000 元(丢失更新)

 

   

A事务在撤销时,“不小心”将B事务已经转入账户的金额给抹去了。 

    第二类丢失更新 

A事务覆盖B事务已经提交的数据,造成B事务所做操作丢失:   

时间

转账事务A

取款事务B

T1

 

开始事务

T2

开始事务

                         

T3

               

查询账户余额为1000元    

T4

查询账户余额为1000元

                         

T5

 

取出100元把余额改为900元

T6

 

提交事务           

T7

汇入100元

 

T8

提交事务

 

T9

把余额改为1100 元(丢失更新)

 

 

    上面的例子里由于支票转账事务覆盖了取款事务对存款余额所做的更新,导致银行最后损失了100元,相反如果转账事务先提交,那么用户账户将损失100元。

 

<html>没有匹配ostream(即 ostream)和function-overload-set类型的实参的可行 operator<<。<br/>考虑的候选项:<br/>ostream::__ostream_type &amp;operator<<(ostream::__ostream_type &amp;(*__pf)(ostream::__ostream_type &amp;)) (class basic_ostream<char, char_traits<char>> 中)<br/>1st实参 count 的转换格式错误: 无法将function-overload-set转换为形参类型 ostream::__ostream_type &amp;(*)(ostream::__ostream_type &amp;)<br/>ostream::__ostream_type &amp;operator<<(ostream::__ios_type &amp;(*__pf)(ostream::__ios_type &amp;)) (class basic_ostream<char, char_traits<char>> 中)<br/>1st实参 count 的转换格式错误: 无法将function-overload-set转换为形参类型 ostream::__ios_type &amp;(*)(ostream::__ios_type &amp;)<br/>ostream::__ostream_type &amp;operator<<(ios_base &amp;(*__pf)(ios_base &amp;)) (class basic_ostream<char, char_traits<char>> 中)<br/>1st实参 count 的转换格式错误: 无法将function-overload-set转换为形参类型 ios_base &amp;(*)(ios_base &amp;)<br/>ostream::__ostream_type &amp;operator<<(long __n) (class basic_ostream<char, char_traits<char>> 中)<br/>1st实参 count 的转换格式错误: 无法将function-overload-set转换为形参类型 long<br/>ostream::__ostream_type &amp;operator<<(unsigned long __n) (class basic_ostream<char, char_traits<char>> 中)<br/>1st实参 count 的转换格式错误: 无法将function-overload-set转换为形参类型 unsigned long<br/>ostream::__ostream_type &amp;operator<<(bool __n) (class basic_ostream<char, char_traits<char>> 中)<br/>1st实参 count 的转换格式错误: 无法将function-overload-set转换为形参类型 bool<br/>ostream::__ostream_type &amp;operator<<(short __n) (class basic_ostream<char, char_traits<char>> 中)<br/>1st实参 count 的转换格式错误: 无法将function-overload-set转换为形参类型 short<br/>ostream::__ostream_type &amp;operator<<(unsigned short __n) (class basic_ostream<char, char_traits<char>> 中)<br/>1st实参 count 的转换格式错误: 无法将function-overload-set转换为形参类型 unsigned short<br/>ostream::__ostream_type &amp;operator<<(int __n) (class basic_ostream<char, char_traits<char>> 中)<br/>1st实参
最新发布
07-17
<think>我们正在处理一个C++编译错误:`error: no operator<< matches the argument types ostream and function-overload-set`。这个错误通常发生在尝试将函数名(即函数重载集)传递给`operator<<`时,因为编译器无法确定使用哪个重载函数。 ### 问题分析 在C++中,函数重载会创建一个函数重载集(function-overload-set),即多个同名函数。当我们只写函数名而不带参数时,它代表的是这个重载集,而不是一个具体的函数。`operator<<`期望一个具体的函数指针或可调用对象,但无法处理一个重载集。 例如,假设有以下两个重载函数: ```cpp void func(int); void func(double); ``` 当我们写`std::cout << func;`时,`func`是一个重载集,编译器无法确定我们想使用哪个`func`,因此会报错。 ### 解决方案 要解决这个问题,我们需要明确指定使用哪个重载函数。可以通过以下方式之一: 1. **使用显式类型转换**:将函数重载集转换为具体的函数指针类型。 2. **使用lambda表达式**:包装函数调用并指定参数。 #### 方法1:显式类型转换 通过将函数名强制转换为特定的函数指针类型,来消除歧义。 ```cpp // 假设我们有两个重载函数 void func(int) { std::cout << "int" << std::endl; } void func(double) { std::cout << "double" << std::endl; } int main() { // 错误:函数重载集无法确定 // std::cout << func; // 正确:显式指定函数指针类型 std::cout << static_cast<void(*)(int)>(func); // 或者 void (*func_ptr)(int) = func; std::cout << func_ptr; } ``` #### 方法2:使用lambda表达式 如果目的是调用函数并输出结果,而不是输出函数地址,那么可以使用lambda表达式来调用特定重载。 ```cpp int main() { // 使用lambda调用func(int) std::cout << [](){ func(42); return ""; }(); // 或者直接调用并输出结果(如果函数有返回值) // 但注意,这里我们输出的是函数调用的结果,而不是函数本身 } ``` ### 注意事项 - 如果只是想输出函数的地址,那么必须通过类型转换指定具体重载。 - 如果希望调用函数并输出其返回值,那么应该直接调用函数并传递参数,而不是传递函数名。 ### 引用分析 在引用[2]中,我们看到一个重载`operator<<`的例子,它是通过友元函数实现的。但是这里的问题不是重载`operator<<`,而是如何将一个函数重载集传递给已有的`operator<<`。引用[4]展示了一个使用SFINAE检测类型是否可打印的例子,但与本问题关联不大。 ### 总结 错误`no operator<< matches the argument types ostream and function-overload-set`的解决关键在于明确指定函数重载集中的具体函数。通过类型转换或lambda表达式可以解决。 §§相关问题§§ 1. C++中函数重载集(function-overload-set)是什么? 2. 如何获取C++重载函数的地址? 3. 除了类型转换,还有哪些方法可以解决函数重载集的二义性问题?</think>### C++编译错误:`no operator<< matches the argument types ostream and function-overload-set` 这个错误发生在尝试将**函数重载集**(function-overload-set)传递给`std::ostream`的`operator<<`时。根本原因是编译器无法确定使用哪个重载函数,导致类型不匹配。以下是详细分析和解决方案: --- #### 错误原因分析 1. **函数重载集**:当存在多个同名函数(重载函数)时,单独使用函数名(如`func`)会形成一个**重载集**,它不是具体的函数指针。 ```cpp void print(int); // 重载1 void print(double); // 重载2 std::cout << print; // 错误:print是重载集,不是具体函数 ``` 2. **`operator<<`的限制**:`std::ostream::operator<<`无法处理重载集,因为它需要: - 具体函数指针(如`void(*)(int)`) - 或可调用对象(如lambda) - 但**不能是未解析的重载集**。 3. 典型错误信息: ``` error: no match for 'operator<<' (operand types are 'std::ostream' and '<unresolved overloaded function type>') ``` --- #### 解决方案 ##### 方法1:显式指定函数类型(推荐) 通过强制类型转换明确选择重载版本: ```cpp std::cout << static_cast<void(*)(int)>(print); // 明确选择print(int) ``` ##### 方法2:使用函数指针变量 提前声明具体函数指针: ```cpp void (*func_ptr)(int) = print; // 绑定到print(int) std::cout << func_ptr; // 输出函数地址 ``` ##### 方法3:Lambda包装(需调用函数) 如果需要调用函数而非获取地址: ```cpp std::cout << [](){ print(42); return ""; }(); // 调用print(int)并返回空字符串 ``` --- #### 关键点说明 1. **为什么需要明确类型?** C++要求函数指针类型必须完全匹配,重载集无法隐式转换到具体指针类型[^2]。 2. **何时会遇到此问题?** 常见场景: - 调试时输出函数名:`std::cout << func_name` - 模板中传递函数名但未实例化具体类型 - 函数作为参数传递时未指定类型 3. **与命名空间的关系** 如果函数位于命名空间内,需明确限定作用域(如`std::cout << ns::print`),否则可能因ADL(参数依赖查找)导致更复杂的重载解析问题[^1]。 --- #### 示例修正 错误代码: ```cpp void foo(int) {} void foo(double) {} int main() { std::cout << foo; // 错误! } ``` 修正后: ```cpp std::cout << static_cast<void(*)(int)>(foo); // 正确 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值