在调试模式下出现了C++编译错误,但在发布模式下没有。

4
我正在尝试编译一个小的COM dll(使用Visual Studio 2008 Pro),在发布版中编译很好,但是当我尝试在调试模式下编译它时,出现了编译错误:
错误C2664:'bool(MyClass&,double)':无法将参数2从'MyClass'转换为'double'。
现在,这个错误来自代码中的一行,我在这里执行以下操作(请注意,someValueThatIsADouble是double类型):
std::vector<MyClass>::iterator iter = std::lower_bound(MyVector.begin(), MyVector.end(), someValueThatIsADouble, less);

而 less 函数的定义如下:

bool less(MyClass& a, double b);

我不明白为什么会出现这个错误,如果这个错误有一个很好的原因,那么为什么我只在Debug(而不是Release中)看到了它?当在Release中编译时,dll可以正常运行且没有崩溃。此外,我检查过了,没有#ifdef DEBUG或其他能够更改在debug和release中编译的代码的东西。

编辑:

这段代码不是我自己写的,这是一个我不太了解的算法,所以我不知道double值应该代表什么,并且我不想改变less函数内部的逻辑来接收MyClass作为第二个参数。

class MyClass
{
public :
    MyClass(): _dValue1(0.0),_dValue2(0.0),_dValue3(0.0)
    {
    }
    MyClass(double dValue1, double dValue3, double dValue2): _dValue2(dValue2),_dValue3(dValue3),_dValue1(dValue1)
    {
    }
    ~MyClass() {}
    double getValue1() {return _dValue1;}
    double getValue3() {return _dValue3;}
    double getValue2() {return _dValue2;}
    double _dValue1;
    double _dValue3;
    double _dValue2;

public:

    friend class vector<MyClass>; 


int compare(const MyClass & t1, const MyClass & t2)
{
  if (t1._dValue1 < t2._dValue1)
    return -1;
  else if (t2._dValue1 < t1._dValue1)
    return 1;
  else
    return 0;
}

bool operator> (const MyClass & rhs)
{
    if (  _dValue1 > rhs._dValue1)
        return true;
    else 
        return false;
}

bool operator< (const MyClass & rhs)
{
    if (  _dValue1 < rhs._dValue1)
        return true;
    else 
        return false;
}

};

编辑:

MSalters的回答表明,谓词的调试和发布实现不同,这使得在我的情况下它在发布中编译而在调试中没有编译(因为代码不太整洁,不应该使用具有2种不同类型的比较函数)。我为了能够在调试中使用此代码所做的hack也是在任何包含之前放置此行(请注意,首选解决方案应该是拥有更好的比较函数,但在我的情况下不可能):

#define _HAS_ITERATOR_DEBUGGING 0 

如果您将“const”添加到所有常量函数中,那将是很好的。 - Kerrek SB
3个回答

2
错误信息表明您使用了 MSVC。它的库实现在谓词上包含调试检查。特别是对于偏序谓词(如您的less),我认为它测试 Pred(a,b) && Pred(b,a) == false 是否成立。显然这里行不通。
(谓词的常见错误之一是人们定义了一个顺序,使得 a<bb<a 都成立。有许多 <algorithm> 在这种情况下会出问题,这就是为什么现在有一些调试检查来防止这些错误。但是如果您实际上设法在运行时传递了一对错误的 a,b 值,它们只能捕捉运行时的错误,无法在编译时捕捉理论上的错误)

啊,是的,这很有可能,谢谢!那么,我能否通过某种方式(可能是黑客方式)使用提供的代码进行调试构建,或者我必须绝对尝试弄清楚如何编写正确的运算符? - Carl
1
这应该永远不会成功,因为每当a == b时它将计算为false。但是,也许它测试了类似于Pred(a, b) => !Pred(b, b)的东西。 - b.buchhold
STL错误检查旨在发现像您这样的错误;您可以关闭它。有关详细信息,请参阅MSDN。(调试和发布实际上只是预定义的选项集。通常可以进行微调。例如,大多数专业人员也会为发布版本构建.PDB文件) - MSalters
@ b.buchhold:糟糕,我从记忆中弄错了反身性测试。颠倒了。逻辑是你不能同时拥有a<bb<a - MSalters
在我的情况下,即使我们的发布配置构建了PDB文件,它仍然无法显示我们在调试配置中遇到的所有错误。特别是,在调试构建中,我们只会得到这个错误:Error C4716 [function template name here] must return a value。我非常希望学习如何使我们的发布配置显示与调试相同的错误。 - Scott Hutchinson

1
template<class ForwardIterator, class Type, class BinaryPredicate>
ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last, const Type& val, BinaryPredicate comp);

first:一个前向迭代器,指定要搜索的范围中第一个元素的位置。

last:一个前向迭代器,指定要搜索的范围中最后一个元素之后的位置。

val:正在搜索排序范围中其第一个位置或可能的第一个位置的值。

comp:用户定义的谓词函数对象,定义了一个元素小于另一个元素的意义。 二元谓词需要两个参数,当满足条件时返回 true,未满足时返回 false。

它在发布模式下编译是因为 std 的发布实现中有一些检查被停用了。但不应该编译:val 应该是 MyClass 类型,而不是 double 类型,这样 less 即使在发布模式下也无法编译。


1

尝试使用:

bool less(const MyClass& a, const MyClass& b);

我应该提到我不想改变less函数。刚刚编辑了我的问题。 - Carl
提供给lower_bound调用的less函数用于比较给定集合中的两个项:由于该集合是MyClass的集合,因此less函数必须取两个MyClass实例的引用。您能否提供MyClass的声明,也许在其上定义了一些特定的运算符。 - rlods
这也是我的第一反应,但如果是这样的话,为什么在发布模式下它可以编译通过呢? - Carl
因为类声明中可能定义了一些类型转换操作符...所以您应该提供 MyClass 的声明。 - rlods
someValueThatIsADouble 是 double 类型吗? - rlods

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接