简体   繁体   中英

C++ behavior that I don't understand

My friends and I were playing with the C++ language. While doing so, we encountered something we couldn't understand.

Here is the code:

#include <vector>
#include <iostream>

void print(std::vector<char> const &input)
{
    std::cout << input.size();
    for (int i = 0; i < input.size(); i++)
    {
        std::cout << input.at(i) << " - ";
    }

}

int main()
{
    char cha = 'A';
    char chb = 'B';
    char * pcha = &cha;
    char * pchb = &chb;
    try
    {
        std::vector<char> a = {pcha, pchb};
        //std::vector<char> a = {pchb, pcha};
        print(a);

    }
    catch(std::exception e)
    {
        std::cout << e.what();
    }
}

Output for this code:

A

When I comment out this first line try block and uncomment the second line, which comes to this:

try
{
    // std::vector<char> a = {pcha, pchb};
    std::vector<char> a = {pchb, pcha};
    print(a); 
}

Output becomes:

std:exception

I thought maybe the this occurs because of the different padding and alignments of the declared variables (char, char*), yet still didn't understand. You can find the code here to play around. Thanks in advance.

std::vector<char> a = {pcha, pchb};

Here, you use the constructor of vector that accepts two iterators to a range. Unless the end iterator is reachable from the begin one, the behaviour of the program is undefined. Your two pointers are not iterators to the same range (ie elements of an array), so one is not reachable from the other. Therefore the behaviour of the program is undefined.

These would be correct:

std::vector<char> a = {cha, chb}; // uses initializer_list constructor

// or
char arr[] {cha, chb};
char * pcha = std::begin(arr);
char * pchb = std::end(arr);
std::vector<char> a = {pcha, pchb}; // uses the iterator constructor

@eerorika's answer explains your mistake.

However, I would like to dissuade you, and other readers, from using the second part of the his(?) corrected code snippet - not because it's incorrect, but because it's problematic coding practice:

  1. I accept Nicolai Jossutis' suggestion of trying to uniformly initialize variables with curly brackets and no equals since (eg. mytype myvar {my_initializer}; ).
  2. Freestanding pointers are dangerous beasts. Try to avoid them altogether, or minimize their existence to where you really need them. After all, you were "tempted" to use those pointers in an inappropriate way... so,
     char arr[] {cha, chb}; std::vector<char> a = {std::begin(arr), std::end(arr)};
  3. Don't create a dummy container just to create the one you really want. Just stick with the first line in @eerorika's suggestion (without the equals sign):
     std::vector<char> a {cha, chb};
  4. In fact, unless you really need it - you probably don't even want to create a variable-length container. So perhaps just
    std::array<char, 2> a {cha, chb};
    or with C++17's template argument deduction:
     std::array a {cha, chb};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM