使用循环和函数

时间:2016-09-07 18:46:30

标签: c++ loops dictionary memory

我是C ++的初学者,但我正在尝试编写Rainmeter插件,基本上可以执行以下操作:

  1. 扫描Rainmeter选项设置的目录中的所有文件。
  2. 过滤掉所有非...的目录,并仅处理这些目录。
  3. 将一些数据添加到map,主要是计算或修复,只有直接受当前正在处理的目录影响的名称。
  4. 将整个内容写入ini格式的文件(这是使用map的原因)。
  5. 出于调试原因,我使用的是控制台而不是实际的文件流。这就是我注意到这个问题的方法。出于一些神秘的原因,可能由于物体超出范围而引用到期,最终输出完全搞砸了 首先,它只包含一个条目,无论我用什么方法迭代它。现在它变得奇怪了。在两个地方,它使用最后找到的目录的名称,在另外两个地方,它使用第一个找到的目录的名称。无论我尝试什么,这个输出都不会改变。我已经尝试将循环内部的代码放入一个单独的函数并返回,使用指针和显式内存分配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\Barabcdef的{​​{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-whilestylelmuAction均指代他们第一个值,只有最后一个条目实际显示出来。

    最后,我已经达到了想法不足的地步,所以我来到了这里。

1 个答案:

答案 0 :(得分:1)

此行为的原因是地图中的const TCHAR*个键。当std::map比较键值以确定放置数据的位置时,它不会使用字符串name引用;

相反,它将比较指针值本身 - 对应于ffd.cFileName的内存地址,并且在整个范围内保持相同,这将导致单个std::map条目。

此外,当地图中已存在密钥时,std::map::insert不执行任何操作,这解释了数据对应于第一个条目的事实。至于密钥本身,它总是等于ffd.cFileName,因此它指向循环文件名的数据,并将停在最后一个。

最简单(也是正确)的解决方法就像NathanOliver所说 - 完全放弃TCHAR*或至少放在std::map等,然后使用std::wstring