【问题标题】:Getting "Debug Assertion Failed!" for set comparator得到“调试断言失败!”用于设置比较器
【发布时间】:2011-04-28 18:44:48
【问题描述】:

我知道类似问题已在此链接Help me fix this C++ std::set comparator得到解答 但不幸的是,我面临着完全相同的问题,我无法理解其背后的原因,因此需要一些帮助来解决它。

我使用的是 VS2010,我的发布二进制运行良好,没有任何问题,但调试二进制报告:

我的比较器如下所示:

struct PathComp {
    bool operator() (const wchar_t* path1, const wchar_t* path2) const
    {
        int c = wcscmp(path1, path2);
        if (c < 0 || c > 0) {
            return true;
        }
        return false;
    }
};

我的集合是这样声明的:

set<wchar_t*,PathComp> pathSet;

有人能告诉我为什么我的调试二进制文件在这个断言上失败了吗?是因为我使用 wcscmp() 函数来比较存储在我的集合中的宽字符串吗?

提前致谢!!!

【问题讨论】:

  • xtree 的第 960 行或附近有什么?
  • @960: _Addleft = _DEBUG_LT_PRED(this-&gt;comp, this-&gt;_Kfn(_Val), this-&gt;_Key(_Trynode)); // favor right end

标签: c++ c++-standard-library


【解决方案1】:

std::set 需要一个有效的比较器,其行为类似于 operator&lt;std::less

std::set 代码检测到您的 operator

确实:您的比较器看起来像 operator!=,而不像 operator&lt;

operator&lt; 应遵循的规则之一是,a&lt;bb&lt;a 不能同时为真。在你的实现中,它是。

将您的代码更正为:

bool operator() (const wchar_t* path1, const wchar_t* path2) const
{  
  int c = wcscmp(path1, path2);
  return (c < 0);
}

你应该没事的。

【讨论】:

  • 打败我。每当您看到 if (x &lt; 0 || x &gt; 0) 时,我都会担心为什么不使用 if (x != 0)(或其他形式的单一直接比较)。
【解决方案2】:

问题在于您的比较器不会产生严格弱排序。它应该只对“更少”的路径真正返回 true - 而不是所有不同的路径。改成:

struct PathComp {
    bool operator() (const wchar_t* path1, const wchar_t* path2) const
    {
        int c = wcscmp(path1, path2);
        if (c < 0) {  // <- this is different
            return true;
        }
        return false;
    }
};

或者,仅使用 c &gt; 0 也可以 - 但该集合将具有相反的顺序。

算法需要知道更小和更大之间的区别才能工作,只是不等并不能提供足够的信息。 如果没有小于/大于信息,集合不可能维持顺序 - 但这就是集合的全部意义所在。

【讨论】:

    【解决方案3】:

    在花了更多时间之后,我们最终决定采用另一种对我有用的方法。

    所以我们使用这种方法将 wchar_t* 转换为字符串:

    // Converts LPWSTR to string
    bool convertLPWSTRToString(string& str, const LPWSTR wStr)
    {
        bool b = false;
        char* p = 0;
        int bSize;    
        // get the required buffer size in bytes
        bSize = WideCharToMultiByte(CP_UTF8,
            0,
            wStr,-1,
            0,0,
            NULL,NULL);     
        if (bSize > 0) {
            p = new char[bSize];
            int rc = WideCharToMultiByte(CP_UTF8,
                0,
                wStr,-1,
                p,bSize,
                NULL,NULL);
            if (rc != 0) {
                p[bSize-1] = '\0';
                str = p;
                b = true;
            }
        }
        delete [] p;
        return b;
    }
    

    然后将该字符串存储在集合中,通过这样做,我不必担心比较存储的元素以确保所有条目都是唯一的。

    // set that will hold unique path
    set<string> strSet;
    

    所以我所要做的就是:

    string str;
    convertLPWSTRToString(str, FileName);
    // store path in the set
    strSet.insert(str);
    

    虽然我在使用a set comparator (PathComp) for set<wchar_t*,PathComp> pathSet; 时仍然不知道是什么导致了“Debug Assertion Failed”问题

    【讨论】:

    • @Vivart 这实际上不是一个答案,这是我们为解决问题而采取的一种解决方法。因此,我仍在寻找有人回答问题中“调试断言失败”背后的原因。 :-)
    • 为什么你要转换为 UTF-8 而不是简单地将 std::wstring 存储在地图中?它具有与std::string 完全相同的功能(实际上它是同一basic_string 模板的不同特化),但基于wchar_t。
    • 哦,为什么要在堆上分配临时缓冲区?您可以简单地 str.resize(bSize) 将字符串分配给它的缓冲区并直接格式化为 &amp;str[0] (以及 str.resize(bSize - 1) 从末尾修剪 \0,因为 std::string 可能包含 \0字节。
    猜你喜欢
    • 1970-01-01
    • 2016-07-29
    • 1970-01-01
    • 2021-10-19
    相关资源
    最近更新 更多