我是一个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版本(现在我只得到投射警告和错误)的情况下获得编译器警告这样的错误吗?
答案 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)
swprintf
可能会溢出缓冲区。(wchar_t*)search_path
是一个多余的演员
如果你不需要它们,就不要打破大枪。if(! (fd.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY) )
表示您只忽略没有有趣属性的目录。fullPath += std::wstring(fd.cFileName);
另一个多余的演员。names.push_back((wchar_t*)fullPath.c_str());
将指向fullpath
的内部缓冲区的指针推送到names
,即使它会在块的末尾被销毁。您应该做的是将签名更改为
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);
如果您不了解对象的范围,请不要将对象的引用存储到列表中。