Search code examples
c++arraystemplatespointersconst-char

counting algorithm and pointer types


I wrote the following code as an exercise about function templates and template specializations. It's a function that counts how many objects of a given type are present in a 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;
}

I wrote the code in the specialization because I want to know if every character in a word is the same as the given literal. To my surprise, if I comment out the specialization and let the compiler instantiate the original template, it works even for the const char arrays:

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

How could it possibly be?


Solution

  • I use the code in my main function in order to test it, but, to my surprise, if I comment out the specialization and let the compiler instantiate the original template,it works even for the const char arrays (the type of string literal)! How could it possibly be?


    The standard doesn't specify that string literals that contains the same sequence of characters have to be stored in the same memory location, as per §2.13.5/16:

    Evaluating a string-literal results in a string literal object with static storage duration, initialized from the given characters as specified above. Whether all string literals are distinct (that is, are stored in non-overlapping objects) and whether successive evaluations of a string-literal yield the same or a different object is unspecified.

    (emphasis mine)

    but this implementation is allowed, and it's what's happening here: each literal string "hej" is stored in the same memory address, so == on const char* is checking wether the address is the same and yielding true.


    To "prove" this we just need to take a look at this example:

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

    Live demo

    This yields 5 due to the fact that there are 5 literals "hej" in the vector. But if we add another char array with the same exact chars in the literal, that we know should have a different address:

    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

    Then we see that the count doesn't change.