将值推送到指针向量具有垃圾值

时间:2014-12-05 05:12:58

标签: pointers visual-c++ vector

我是一个C ++ noob,我编写了一个方法来获取文本文件名,包括给定目录中的完整路径。它在vector<wchar_t*> names上给出了垃圾值。我使用VS2010调试器并分析了值。看起来指针超出了范围。在正式的C ++参考文献中,它表示push_back()复制值,看起来像我正在推动指针,它只是复制指针值。

static std::vector<wchar_t*> getFileNames(wchar_t* folder) // ex: c:\\textfiles\\My
{
    using namespace std;

    vector<wchar_t*> names;
    wchar_t search_path[200];
    swprintf(search_path, L"%s\\*.txt", folder); //  ex: c:\\textfiles\\My\\*.txt

    WIN32_FIND_DATA fd; 
    HANDLE hFind = FindFirstFile((wchar_t*)search_path, &fd); 

    if(hFind != INVALID_HANDLE_VALUE) 
    { 
        do 
        { 
            if(! (fd.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY) ) 
            {
                std::wstring fullPath(folder);
                fullPath += L"\\";
                fullPath += std::wstring(fd.cFileName); // cFilename has something like Info.txt
                names.push_back((wchar_t*)fullPath.c_str());
            }
        }while(FindNextFile(hFind, &fd));  //goes out of scope and values become garbage
        FindClose(hFind); 
    }
    return names; //vector with garbage values
}

是否有可能将wchar_t*推入到向量中,更好的解决方法而不是动态分配内存或使用堆变量?

我可以在VS2010或任何VS版本(现在我只得到投射警告和错误)的情况下获得编译器警告这样的错误吗?

3 个答案:

答案 0 :(得分:1)

理想情况下,您应该在向量中存储类对象,而不是字符指针(或wchar_t指针)。你可以做到,但它需要一些额外的工作。那是你错过的部分。

您所看到的问题正是您所描述的:当wstring超出范围时,wstring对象拥有的字符数组将被销毁。通过使用wstring :: c_str(),您不是要创建字符数组的独立副本,而只是查看它已经为自己使用创建的那个。

所以你需要一种方法来保持字符数组更长时间。要么你可以使用wstring,要么你需要将字符数组复制到你自己的数组中。

最小的改变是这样的:

std::wstring fullPath(folder);
fullPath += L"\\";
fullPath += std::wstring(fd.cFileName); // cFilename has something like Info.txt
wchar_t *wsz = new wchar_t[fullPath.size() + 1];
wcsncpy(wsz, fullPath.c_str(), fullPath.size());
names.push_back(wsz);

这足以让你的字符串进入向量,但因为你正在使用字符指针,所以你也有责任清理它们。所以当你完成使用向量时,你需要迭代并删除它们中的每一个,然后才能销毁这个向量。

正如我在下面的评论中提到的,使用std :: vector要简单得多。如果必须使用wchar_t *,有些库可以帮助您处理内存管理部分。例如,您可以查看Boost Smart Pointer库。

答案 1 :(得分:1)

  1. swprintf可能会溢出缓冲区。
  2. (wchar_t*)search_path是一个多余的演员 如果你不需要它们,就不要打破大枪。
  3. if(! (fd.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY) )表示您只忽略没有有趣属性的目录。
  4. fullPath += std::wstring(fd.cFileName);另一个多余的演员。
  5. names.push_back((wchar_t*)fullPath.c_str());将指向fullpath的内部缓冲区的指针推送到names,即使它会在块的末尾被销毁。
  6. 您应该做的是将签名更改为

    static std::vector<std::wstring> getFileNames(std::wstring folder)
    

    或者至少

    static std::vector<std::unique_ptr<wchar_t>> getFileNames(wchar_t* folder)
    

    利用RAII并减少出错的机会。

    在任何情况下,您都应该重写该函数,并且应该在内部利用标准库。

    作为一个例子,使用适当的原型:

    static std::vector<std::wstring> getFileNames(std::wstring folder) {
        std::vector<std::wstring> names;
        WIN32_FIND_DATA fd; 
        HANDLE hFind = FindFirstFile((folder+L"\\*.txt").c_str(), &fd); 
        if(hFind == INVALID_HANDLE_VALUE)
            return names;
    
        auto lam = [](HANDLE* p){FindClose(*p);}
        std::unique_ptr<HANDLE, decltype(lam)> guard(&hFind, lam);
    
        folder += L"\\"; 
        do {
            if(! (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
                names.push_back(folder+fd.cFileName);
        } while(FindNextFile(hFind, &fd));
        return names;
    }
    

答案 2 :(得分:0)

变量 fullPath 是一个局部变量。 它超出了范围。 这就是指针变成垃圾的原因。

将动态内存分配为

vector<wstring*> names;// instead of vector<wchar_t*> names;
std::wstring *fullPath = new wstring(folder);

如果您不了解对象的范围,请不要将对象的引用存储到列表中。