简体   繁体   中英

unable to modify a vector of const wchar *

I have a function that converts a list of strings to a vector of const wchar_t *.

void convertListtoVector(std::vector<const wchar_t *>& messageInserts)
{
    std::list<std::wstring> Inserts;
    Inserts.push_back(L"str1");
    Inserts.push_back(L"str2");
    Inserts.push_back(L"str3");

    std::list<std::wstring>::iterator itr;
    
    for (itr = Inserts.begin(); itr != Inserts.end(); itr++) {
        messageInserts.push_back((*itr).c_str());
    
    }
}

I am calling it like this:

std::vector<const wchar_t *> msg;
convertListtoVector(msg);

But after the function is exectuted I have a vector of 3 empty strings. When I debugged my code I noticed that inside the function the vector is getting updated with the strings but after the function returns I see the size has change from 0 to 3 but all strings are empty "". I want the vector with the strings. Please let me know where I am going wrong. Thanks in advance.

When building your program with address sanitizer, we get a memory error detected: AddressSanitizer: heap-use-after-free .

Generally in modern c++, we don't recommend using raw pointers: we prefer to use containers.

You have stored the string address why owned by local std::list after the function returns, these addresses are not accessible (You got an empty string while printing, but actually it may crash), to fix it we can have 3 choices:

  1. to make a copy
void convertListtoVector(std::vector<std::wstring>& messageInserts)
{
    std::list<std::wstring> Inserts;
    Inserts.push_back(L"str1");
    Inserts.push_back(L"str2");
    Inserts.push_back(L"str3");

    std::list<std::wstring>::iterator itr;
    
    for (itr = Inserts.begin(); itr != Inserts.end(); itr++) {
        messageInserts.push_back(*itr);
    
    }
}

or with STL algorithm

void convertListtoVector(std::vector<std::wstring>& messageInserts)
{
    std::list<std::wstring> Inserts;
    Inserts.push_back(L"str1");
    Inserts.push_back(L"str2");
    Inserts.push_back(L"str3");
    messageInserts.insert(messageInserts.end(), Inserts.begin(), Inserts.end());
}
  1. to move from the local container, since the local list won't be need any more, for large strings, to move them will get performance improvement
void convertListtoVector(std::vector<std::wstring>& messageInserts)
{
    std::list<std::wstring> Inserts;
    Inserts.push_back(L"str1");
    Inserts.push_back(L"str2");
    Inserts.push_back(L"str3");
    
    for (itr = Inserts.begin(); itr != Inserts.end(); itr++) {
        messageInserts.push_back(std::move(*itr));
    }
}

or with STL algorithm

void convertListtoVector(std::vector<std::wstring>& messageInserts)
{
    std::list<std::wstring> Inserts;
    Inserts.push_back(L"str1");
    Inserts.push_back(L"str2");
    Inserts.push_back(L"str3");
    messageInserts.insert(messageInserts.end(), std::make_move_iterator(Inserts.begin()), std::make_move_iterator(Inserts.end()));
}
  1. to make the local list static, but this maybe error prone:
void convertListtoVector(std::vector<const wchar_t*>& messageInserts)
{
    static std::list<std::wstring> Inserts;
    Inserts.push_back(L"str1");
    Inserts.push_back(L"str2");
    Inserts.push_back(L"str3");

    std::list<std::wstring>::iterator itr; 
    for (itr = Inserts.begin(); itr != Inserts.end(); itr++) {
        messageInserts.push_back(itr->c_str());
    }
}

Your vector stores a pointer to string whose lifetime is managed by std::list . When list as local variable is deleted, all managed strings are also deleted, and you left with dangling pointers in vector.

You have to make a deep copy of strings content of list:

void convertListtoVector(std::vector<const wchar_t *>& messageInserts)
{
    std::list<std::wstring> Inserts;
    Inserts.push_back(L"str1");
    Inserts.push_back(L"str2");
    Inserts.push_back(L"str3");

    std::list<std::wstring>::iterator itr;
    
    for (itr = Inserts.begin(); itr != Inserts.end(); itr++) {
        wchar_t *cloneStr = new wchar_t[wcslen(itr->c_str())+1];
        wcscpy(cloneStr,itr->c_str());
        messageInserts.push_back(cloneStr);
    }
}

int main(){
    std::vector<const wchar_t *> msg;
    convertListtoVector(msg);
    for (const wchar_t* str : msg) {
        std::wcout << str << std::endl;
        delete[] str;
    }
}

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