我是C ++的初学者,但我正在尝试编写Rainmeter插件,基本上可以执行以下操作:
.
或..
的目录,并仅处理这些目录。 map
,主要是计算或修复,只有直接受当前正在处理的目录影响的名称。map
的原因)。 出于调试原因,我使用的是控制台而不是实际的文件流。这就是我注意到这个问题的方法。出于一些神秘的原因,可能由于物体超出范围而引用到期,最终输出完全搞砸了
首先,它只包含一个条目,无论我用什么方法迭代它。现在它变得奇怪了。在两个地方,它使用最后找到的目录的名称,在另外两个地方,它使用第一个找到的目录的名称。无论我尝试什么,这个输出都不会改变。我已经尝试将循环内部的代码放入一个单独的函数并返回,使用指针和显式内存分配new
几乎无处不在,并故意不在那些上调用delete
来尝试让它们保持活着,并在某些地方使用shared_ptr
。
这是相关部分使用的当前代码
typedef std::pair<const TCHAR*, const TCHAR*> kv_pair;
int elem_index = 1;
std::map<const TCHAR*, std::map<const TCHAR*, const TCHAR*>> content;
WIN32_FIND_DATA ffd;
HANDLE hFind;
TCHAR[] measure_name = L"MeasureTest";
TCHAR[] dir = L"C:\\Foo\\Bar";
TCHAR[] searchPath = L"C:\\Foo\\Bar\\*"; //Of course these are actually dynamically sized
hFind = FindFirstFile(searchPath, &ffd);
//Error handling
do {
if((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (*ffd.cFileName != L'.')) {
StringCchCat(dir, wcslen(dir) + wcslen(ffd.cFileName) + 2, L"\\");
StringCchCat(dir, wcslen(dir) + wcslen(ffd.cFileName) + 2, ffd.cFileName);
const TCHAR* name = ffd.cFileName;
const TCHAR* measure_name = data->_measureName;
std::map<const TCHAR*, const TCHAR*>* tmp = new std::map<const TCHAR*, const TCHAR*>;
// BEGIN More or less irrelevant for the actual problem
int col = ((int) elem_index / 5) + 1;
int row = elem_index++ % 5;
TCHAR* style = new TCHAR[wcslen(L"PlaylistGeneral | PlaylistRow1 | PlaylistCol1") + 1];
StringCchPrintf(style, wcslen(L"PlaylistGeneral | PlaylistRow1 | PlaylistCol1") + 1, L"PlaylistGeneral | PlaylistRow%d | PlaylistCol%d", row, col);
TCHAR* lmuAction = new TCHAR[wcslen(L"[!CommandMeasure \"\"]") + wcslen(measure_name) + wcslen(path) + 1];
TCHAR* rmuAction = new TCHAR[wcslen(L"[\"\"]") + wcslen(path) + 1];
StringCchPrintf(lmuAction, wcslen(L"[!CommandMeasure \"\"]") + wcslen(measure_name) + wcslen(path) + 1, L"[!CommandMeasure %s \"%s\"]", measure_name, path);
StringCchPrintf(rmuAction, wcslen(L"[\"\"]") + wcslen(path) + 1, L"[\"%s\"]", path);
// END More or less irrelevant for the problem
tmp->insert(kv_pair(L"Meter", L"String"));
tmp->insert(kv_pair(L"Group", L"Playlist"));
tmp->insert(kv_pair(L"Hidden", L"1"));
tmp->insert(kv_pair(L"Text", name)); // These parts
tmp->insert(kv_pair(L"MeterStyle", style)); // are the
tmp->insert(kv_pair(L"LeftMouseUpAction", lmuAction)); // actual
tmp->insert(kv_pair(L"RightMouseUpAction", rmuAction)); // problem
content.insert(section(name, *tmp));
}
} while (FindNextFile(hFind, &ffd) && elem_index < 30);
//Some more error handling
for (const auto& section : content) {
std::wcout << '[' << current.first << ']' << std::endl;
for (const auto& kv : section.second) std::wcout << kv.first << '=' << kv.second << std::endl;
}
使用名为C:\Foo\Bar
,abc
和def
的{{1}}中的3个文件夹运行此操作,会产生以下输出
ghi
可见,持有[ghi]
Meter=String
Group=Playlist
Hidden=1
Text=ghi
MeterStyle=PlaylistGeneral | PlaylistRow1 | PlaylistCol1
LeftMouseUpAction=[!CommandMeasure MeasureTest "C:\Foo\Bar\abc"]
RightMouseUpAction=["C:\Foo\Bar\abc"]
的密钥使用name
的最后一次迭代中的值,而do-while
,style
和lmuAction
均指代他们第一个值,只有最后一个条目实际显示出来。
最后,我已经达到了想法不足的地步,所以我来到了这里。
答案 0 :(得分:1)
此行为的原因是地图中的const TCHAR*
个键。当std::map
比较键值以确定放置数据的位置时,它不会使用字符串name
引用;
相反,它将比较指针值本身 - 对应于ffd.cFileName
的内存地址,并且在整个范围内保持相同,这将导致单个std::map
条目。
此外,当地图中已存在密钥时,std::map::insert
不执行任何操作,这解释了数据对应于第一个条目的事实。至于密钥本身,它总是等于ffd.cFileName
,因此它指向循环文件名的数据,并将停在最后一个。
最简单(也是正确)的解决方法就像NathanOliver所说 - 完全放弃TCHAR*
或至少放在std::map
等,然后使用std::wstring
。