zoukankan      html  css  js  c++  java
  • Effective Modern C++ 之 避免对以全局引用为参数的函数重载

    考察以下代码:

    std::multiset<std::string> names;           //global data structure
    
    void LogAndAdd(const std::string &name)
    {
        auto now =                              //got current time 
            std::chrono::system_clock::now();
        
        log(now, "logAndAdd");                  //make log entry
        
        names.emplace(name);
    }
        

    这看起来似乎没什么问题. 没错, 实际上这么编译也是可以通过的, 可是还存在优化的空间. 考察以下情况:

    std::string petName = ("Darla");
    LogAndAdd(petName);
    LogAndAdd(std::string("Persephone"));
    LogAndAdd("Patty Dog");

    其中, 只有第一个输入的参数是左值, 第二个是一个右值, 而第三个会先产生一个临时拷贝(所以说也是右值), 但是由于没有相应的函数对应, 调用这三次操作的开销都是拷贝的开销, 咱们本来是可以把后两个移动过去的对不? 所以可以这样:

    template<typename T>
    void LogAndAdd(T &&name)
    {
        auto now = std::chono::system_clock::now();
        log(now, "logAndAdd");
        names.emplace(std::forward<T>(name));
    }

    这下怎么样? 爽! 但是问题来了, 假如需求变了, 名字啥的需要通过索引来查找:

    std::string NameFromIdx(int idx);
    
    void LogAndAdd(int idx)
    {
        auto now = std::chrono::system_clock::now();
        log(now, "logAndAdd");
        names.emplace(NameFromIdx(idx));
    }

    对啊, 就是中间要多一道, 你这不是也实现了吗? 可是问题来了, 扭曲的用户可是什么都能做出来的, 如果你遇到这这么一个人. TA:

    short nameIdx;
    ...
    LogAndAdd(nameIdx);

    那么问题就来了. 怎么, 因为 nameIdx 是个 short(短小) 所以参数为 int 的那个版本就不会接受它, 而使用模板的版本则以它开放的胸怀把它接受了, 当然结果就是一大长串莫名其妙的错误信息.

    同样的, 假如有这么个类:

    class Person
    {
    public:
        tempalte<typename T>
        explicit Person(T &&n)
        : _name(std::forward<T>(n))
        {}
        
        explicit Person(int idx);
        Person(const Person&);
        Person(Person&&);
        ...
    };

    看起来挺严谨, 实际上如果咱们这样:

    Person p("Nancy");      //good name
    auto cloneOfP(p);       //WTF

    对, 又出事了, 这个叫做 Nancy 的女士(不会是男的吧...) p, 人家是个非常量左值(额, non-const lvalue) 所以那几个非模板版本的移动/拷贝 构造函数根本就不知道这是个啥. 所以 Nancy 就被抛给用模板实现的版本了:

    //就是这样
    class Person
    {
    public:
        tempalte<typename T>
        explicit Person(Person &n)
        : _name(std::forward<Person&>(n))
        {}
        
        explicit Person(int idx);
        Person(const Person&);
        Person(Person&&);
        ...
    };

    当然, 就像上面分析的, 当 Nancy 是个常量, 非模板版本的拷贝函数就来接家属了:

    const Person p("Nancy");
    auto cloneOfP(p);           //copy ctor

    可问题是, 总不能项目里都是常量对象吧, 所以具体怎么处理这个棘手的问题, 请看下篇博客.

  • 相关阅读:
    DbgPrint格式 输出
    string 类常用函数[转]
    pragma warning[转]
    连接符
    ubuntu ftp server
    关于dex

    Topology中各函数调用顺序
    C# 错误捕捉
    操作word,Excel,PPT
  • 原文地址:https://www.cnblogs.com/wuOverflow/p/4202594.html
Copyright © 2011-2022 走看看