美文网首页
符号重载让C++负重前行,丑陋不堪,如履薄冰

符号重载让C++负重前行,丑陋不堪,如履薄冰

作者: ClownFreeMan | 来源:发表于2023-03-29 17:33 被阅读0次

不得不说, 符号重载使C++实现了很多优秀的功能。

优点:

比如 智能指针,依赖对指针的赋值来计数,自动析构减少计数,防止指针内存泄露
比如 让代码更简洁,用一个简单的符号 如[], < , ==, () 帮助程序员完成了很多需要手写的函数。写java的一定深有体会

缺点:

把大量问题隐藏在重载的代码中。就好比一个总是溺爱女儿的老父亲,女儿不喜欢释放内存,那我就帮你保护起来。问题的本质是,不按规矩写代码,用再多的补救措施,那个不按规矩来的人依然是漏洞百出的。
再来说代码调试,重载符号的函数怎么跟进怎么看,是不是很麻烦。哪里的一个看是普通的一行代码,蕴含了大量重载符号函数的操作,不禁让程序员吓一跳,就这一行代码怎么发生这么多我不知道的事,还是老老实实写好函数名称,老老实实调用函数接口吧。

看看std boost 模板库里,让人眼花缭乱的源码,都不谈可读性和可理解性,这难道是我们对优秀的定义?不禁困惑,如果我们自己设计通用的模板库,也会把代码写成这样吗?
有幸对比了纯C语言的 list tree 等的纯宏实现,简洁明了可读性高,虽然可能编码习惯和安全性每个人不一样,但对比std容器简直好太多。

举一个例子:

std:set 默认有序,采用红黑树有序存储。可用 < 比较器 和 () 来实现唯一性。 隐含的规则如下

1. f(x,x) = false; 
2. if f(x,y) then !f(y,x)
3. if f(x,y) and f(y,z) then f(x,z)
4. if !f(x,y)&&!f(y,x) then x==y; if x==y and y==z then x==z;

set容器在判定已有元素a和新插入元素b是否相等时,如果采用 less比较器 bool operator() (const myclass& op),是这么做的:
1)将a作为左操作数,b作为有操作数,调用比较函数,并返回比较值
2)将b作为左操作数,a作为有操作数,再调用一次比较函数,并返回比较值。
如果1、2两步的返回值都是false,则认为a、b是相等的,则b不会被插入set容器中;
如果1、2两步的返回值都是true,则可能发生未知行为,
因此,记住一个准则:永远让比较函数对相同元素返回false。

如果有()重载 就使用这个比较傲规则,同样 永远让比较函数对相同元素返回false。

class vector_cmp{
public:
    bool operator()( const std::vector<int> v1,const std::vector<int> v2)
    {
        if (v1.size() != v2.size()) 
            return v1.size() < v2.size();
        if (v1.size() != 3) 
            return false;
        if (v1[0] == v2[0] && v1[1] == v2[1] && v1[2]==v2[2])
            return false;
        if (v1[0] != v2[0])
            return v1[0] < v2[0];
        if(v1[1] != v2[1])
            return v1[1] < v2[1];
        if (v1[2] != v2[2])
            return v1[2] < v2[2];
        return false;
    }
};
void insert_set(std::set<std::vector<int>, vector_cmp>& myset)
{
    std::vector<int> v1 = {1, 2, 3};
    std::vector<int> v2 = {1, 2, 4};
    std::vector<int> v3 = {1, 2, 3};
    std::vector<int> v4 = {3, 4, 8};

    myset.insert(v1);
    myset.insert(v2);
    myset.insert(v3);
    myset.insert(v4);
}

上面这个 set 希望存储不重复的三元组,假设三元组是已经排序好的。 那么问题是, 插入 v1、v2、v3、v4的时候,重载函数()分别运行几次。
答案是0,3,3,4

in operator ()(1,2 , 4)===(1,2 , 3)
in operator ()(1,2 , 3)===(1,2 , 4)
in operator ()(1,2 , 4)===(1,2 , 3)
in operator ()(1,2 , 3)===(1,2 , 3)
in operator ()(1,2 , 3)===(1,2 , 4)
in operator ()(1,2 , 3)===(1,2 , 3)
in operator ()(3,4 , 8)===(1,2 , 3)
in operator ()(3,4 , 8)===(1,2 , 4)
in operator ()(1,2 , 4)===(3,4 , 8)
in operator ()(3,4 , 8)===(1,2 , 4)

总结:

回首细看标准库的源码,再对比现有的优秀的开源C++框架,很明显的问题是开源的普遍在符号重载上有意退避。回想起十年前,搞编译器、系统编译优化的老教授,语重心长的在课堂上大肆批评符号重载,我们还在疑惑是不是他老了接收不了新事物,现在我不怀疑。
凡事有利必有蔽,双刃剑还得利用优良特性,同时避其糟粕。

相关文章

  • C++重载符号

    最近刷一道算法题需要用到运算符重载,在这里mark一下吧:)\n 方法一:友元函数 方法二:类成员函数 ps:友元...

  • 【C++】operator 重载符号

    说说 最近闲时研究下C++发现有个重载符号operator,挺有意思就简单了解下。当然发现operator可以对<...

  • 生活不堪,依旧负重前行

    我90后,无车,无房,无存款,已婚,已育,花呗负的,一个月3000的工资,刚到手没捂热,已经在还花呗的路上。...

  • C++运算符重载

    C++运算符重载的实质:运算符重载的实质就是函数重载或函数多态。运算符重载是一种形式的C++多态。目的在于让人能够...

  • HJ14 字符串排序

     重载less比较符号。  c++的字符串可以直接比较。可以直接调用,最终结果就是按照升序排列。

  • 认清现实热爱生活

    现实就是有潜力,也有不足,有收获,也有失去,整体来说,问题大于发展,负重前行,如临深渊,如履薄冰,焦虑和忧愁,烦恼...

  • c++的运算符重载

    C++中的加号重载:例:实现复数的相加 C++中的前置++重载:例:点的移动 C++中的后置++重载:例:点的移动

  • 《青春》

    青春就应该负重前行,而不是让别人替你负重前行。——《至少做到不要让这个世界改变》

  • 1.2.15_C++ 关系运算符重载

    C++ 重载运算符和重载函数 C++ 语言支持各种关系运算符( < 、 > 、 <= 、 >= 、 == 等等),...

  • 2019-06-02

    让负重前行成为一种习惯!

网友评论

      本文标题:符号重载让C++负重前行,丑陋不堪,如履薄冰

      本文链接:https://www.haomeiwen.com/subject/rxifddtx.html