美文网首页
符号重载让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++负重前行,丑陋不堪,如履薄冰

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