【问题标题】:counting algorithm and pointer types计数算法和指针类型
【发布时间】:2015-08-31 21:42:01
【问题描述】:

我编写了以下代码作为关于函数模板和模板特化的练习。这是一个计算vector 中存在多少给定类型的对象的函数:

template <typename T>
int function(const std::vector<T> &vec, T val) {
    int count = 0;
    for(typename std::vector<T>::const_iterator it = vec.begin(); it != vec.end(); ++it)
        if(*it == val)
            ++count;
    return count;
}

template <>
int function(const std::vector<const char*> &vec, const char* val) {
    int count = 0;
    for(std::vector<const char*>::const_iterator it = vec.begin(); it != vec.end(); ++it) {
        if (std::string(*it) == std::string(val))
            ++count;
    }
    return count;
}

我在专业化中编写代码是因为我想知道单词中的每个字符是否与给定的文字相同。令我惊讶的是,如果我注释掉特化并让编译器实例化原始模板,它甚至适用于 const char 数组:

int main() {
    std::vector<const char*> cvec = {"hi", "hi", "hallo", "hej", "hej", "hi", "hej", "hej", "hej"};
    std::cout << function(cvec, "hej") << std::endl;
}

Live demo

怎么可能?

【问题讨论】:

  • Upside down Jeffrey 在他的回答中解释了这里发生的事情。看到这一点的一个简单方法是定义一个局部变量std::string hej{"hej"};,然后调用function(cvec, hej.c_str()) 并查看结果。在这种情况下,您将在堆上拥有一个单独的“hej”副本,您将获得预期的结果。
  • 我已经简化了问题和代码,并在问题中添加了 SSCCE。如果您觉得编辑改变了问题的含义,请随时回滚到以前的版本。 :)

标签: c++ arrays templates pointers const-char


【解决方案1】:

我在我的 main 函数中使用代码来测试它,但令我惊讶的是,如果我注释掉特化并让编译器实例化原始模板,它甚至适用于 const char 数组(类型字符串字面量)!怎么可能?


该标准没有指定包含相同字符序列的字符串文字必须存储在相同的内存位置,根据 §2.13.5/16:

评估一个字符串文字会产生一个具有静态存储持续时间的字符串文字对象,从上面指定的给定字符初始化。 是否所有字符串文字都是不同的(即,存储在不重叠的对象中)以及字符串文字的连续评估是否产生相同或不同的对象是未指定的 .

(强调我的)

但是这种实现是允许的,这就是这里发生的事情:每个文字字符串"hej" 都存储在相同的内存地址中,所以const char* 上的== 正在检查地址是否相同并产生true。


要“证明”这一点,我们只需要看一下这个例子:

int main() {
    std::vector<const char*> cvec = {"hi", "hi", "hallo", "hej", "hej", "hi", "hej", "hej", "hej"};
    std::cout << function(cvec, "hej") << '\n';
}

Live demo

这会产生 5,因为向量中有 5 个文字 "hej"。但是如果我们在字面量中添加另一个具有相同 chars 的 char 数组,我们知道应该有一个不同的地址:

int main() {
    std::string hej = "hej";
    std::vector<const char*> cvec = {"hi", "hi", "hallo", "hej", "hej", "hi", "hej", "hej", "hej", hej.c_str()};
    std::cout << function(cvec, "hej") << std::endl;
}

Live demo

然后我们看到计数没有改变。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-04
    • 1970-01-01
    • 2019-04-11
    • 2019-03-14
    • 1970-01-01
    • 2023-04-07
    • 1970-01-01
    相关资源
    最近更新 更多