微软也会错,后置++很危险!

本文探讨了在C++中使用VariantCopy和AutoWrap时遇到的问题,特别是关于对象赋值过程中level变量的递增操作导致的意料之外的行为。通过分析,揭示了后置递增操作符在实际应用中的不确定性及其对程序逻辑的影响。
    // Line 11: set screen = doc . parentwindow . screen 
    level=0;//因为是代码片段,我特意加了初始化,以防歧义原来发生代码中没有的
    VariantCopy(&root[++level], &doc);//拷贝doc内容到root[++level]
    AutoWrap(DISPATCH_PROPERTYGET|DISPATCH_METHOD, &root[level+1], root[level++].pdispVal, L"parentwindow", 0);//可以看成root[level++].parentwindow对象赋值给root[level+1]
   //下面的可以不看
    AutoWrap(DISPATCH_PROPERTYGET|DISPATCH_METHOD, &rVal, root[level].pdispVal, L"screen", 0);
    VariantClear(&root[level--]);
    VariantClear(&root[level--]);
    VariantCopy(&screen, &rVal);
    VariantClear(&rVal);

上面的代码来自微软的VB to VC automation Code Converte

大家是不是认为
1、VariantCopy(&root[++level], &doc)是doc对象赋值给root[1]
2、root[1].parentwindow对象赋值给root[2]
其实,我也是这样想的,但是经过跟踪发现root[1].parentwindow对象赋值给了root[3]。

环境:VS2008+Win7

结果是:在第一个AutoWrap中,传给root[1].parentwindow对象赋值给root[3],

事实,我们忽略的一点,根据C++ primer,后置++只是通过返回一个++之前的原值,带来延时++的效果,通过优先级再有差异也是在也是在

[level++]这个括号之中完成的,那么root[level+1], root[level++].pdispVal中的level到底在上面时候++的,level+1之前,还是之后?这个过程,必然在AutoWrap传入压栈参数之前完成,到底谁先谁后?,不知道!在http://blog.youkuaiyun.com/blankman/article/details/149206作者给我指明了方向:没有明确顺序!所以,root[level+1]中的level是多少,完全看编译器和优化的过程了。

微软的VB to VC automation Code Converte估计自己也忽略了。当下面的代码第二个AutoWrap继续引用root[level].pdispVal是自以为是在操作第一个AutoWrap中的root[level+1]取回的对象,实际上,确实在操作一个完全悬空的对象root[2],而第一个AutoWrap取回的对象其实放在了root[3]中。结果就是第二个AutoWrap一直错啊一直错。

在 C++ 中,后置 `++` 重载使用链式连接报通常是由于后置 `++` 运算符的语义以及重载函数的返回值类型导致的。 ### 报原因 后置 `++` 运算符的语义是先返回对象的当前值,然后再对对象进行自增操作。为了实现这个语义,后置 `++` 重载函数通常会返回对象的一个副本(临时对象),而不是对象本身的引用。临时对象是右值,在 C++ 中,右值不能被修改,因此不能作为链式调用的左操作数,从而导致链式连接报。 ### 解决方案 如果需要支持链式连接,可以考虑以下两种方案: #### 1. 返回对象的引用 可以修改后置 `++` 重载函数,使其返回对象的引用而不是临时对象。但这样会改变后置 `++` 运算符的语义,使其行为更像前置 `++` 运算符。 ```cpp #include <iostream> class Counter { private: int value; public: Counter(int val = 0) : value(val) {} // 后置++重载,返回对象引用 Counter& operator++(int) { ++value; return *this; } void print() const { std::cout << "Value: " << value << std::endl; } }; int main() { Counter c(0); (c++)++; c.print(); return 0; } ``` #### 2. 不使用链式连接 如果不想改变后置 `++` 运算符的语义,那么就避免使用链式连接。后置 `++` 本身就不适合链式调用,因为它的设计初衷是先返回当前值再自增。 ```cpp #include <iostream> class Counter { private: int value; public: Counter(int val = 0) : value(val) {} // 后置++重载,返回临时对象 Counter operator++(int) { Counter temp = *this; ++value; return temp; } void print() const { std::cout << "Value: " << value << std::endl; } }; int main() { Counter c(0); c++; c++; c.print(); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值