相关疑难解决方法(0)

什么时候断言应该留在生产代码中?

有一个讨论,在comp.lang.c超过回事++.关于缓和与否的断言,这在C++中默认情况下只在调试中存在的构建,应保持在生产代码或没有.

显然,每个项目都是独特的,所以在这里我的问题是没有这么多是否断言应该保持,但在这情况下,这是值得推荐的/不是一个好主意.

通过断言,我的意思是:

  • 一个运行时检查,用于测试一个条件,当该条件为false时,会显示软件中的错误.
  • 程序停止的机制(可能是在最小的清理工作之后).

我不一定在谈论C或C++.

我自己的观点是,如果你是程序员,但不拥有数据(大多数商业桌面应用程序就是这种情况),你应该保持它们,因为失败的断言显示了一个错误,你不应该去有bug,有可能破坏用户的数据.这会强制您在发货前进行强力测试,并使错误更加明显,从而更容易发现并修复.

你有什么看法/经验?

干杯,

卡尔

在此查看相关问题


回应和更新

嘿格雷厄姆,

断言是错误的,纯粹而简单,因此应该像一个一样处理.由于应该在发布模式下处理错误,因此您不需要断言.

这就是为什么我在谈论断言时更喜欢"bug"这个词.它使事情更加清晰.对我来说,"错误"这个词太模糊了.丢失的文件是错误,而不是错误,程序应该处理它.试图取消引用空指针是一个错误,程序应该承认有些东西闻起来像坏奶酪.

因此,您应该使用断言来测试指针,但是存在具有正常错误处理代码的文件.


稍微偏离主题,但讨论中的一个重点.

作为一个单挑,如果你的断言在失败时闯入调试器,为什么不呢.但是有很多原因导致文件不存在,完全不受代码控制:读/写权限,磁盘已满,USB设备已拔下等等.由于您无法控制它,我觉得断言是不是处理这个问题的正确方法.

卡尔


托马斯,

是的,我有代码完成,并且必须说我非常不同意该特定建议.

假设您的自定义内存分配器搞砸了,并将一些仍然被其他对象使用的内存归零.我碰巧将这个对象定期解除引用的指针归零,并且其中一个不变量是该指针永远不为空,并且你有几个断言以确保它保持这种状态.如果指针突然为空,你会怎么做?你只是if()围绕它,希望它有效吗?

请记住,我们在这里讨论产品代码,因此不会破坏调试器并检查本地状态.这是用户机器上的一个真正的错误.

卡尔

assert

160
推荐指数
7
解决办法
5万
查看次数

何时使用断言以及何时使用异常

大多数时候我会使用异常来检查代码中的条件,我想知道什么时候使用断言是合适的时间?

例如,

Group group=null;
try{
    group = service().getGroup("abc");
}catch(Exception e){
    //I dont log error because I know whenever error occur mean group not found
}

if(group !=null)
{
    //do something
}
Run Code Online (Sandbox Code Playgroud)

你能指出断言如何适应这里吗?我应该使用断言吗?

看起来我从不在生产代码中使用断言,只在单元测试中看到断言.我知道在大多数情况下,我可以使用异常来执行上面的检查,但我想知道"专业"的适当方式.

java exception assertion

114
推荐指数
4
解决办法
4万
查看次数

异常与断言

Java异常处理和使用assert条件之间有什么区别?

众所周知,Assert有两种类型.但什么时候应该使用assert关键字?

java assert

54
推荐指数
4
解决办法
4万
查看次数

异常与断言?

可能重复:
通过断言或异常的合同测试设计?

在决定使用异常而不是断言时(或反之亦然),是否遵循经验法则.现在我只会抛出我认为会在用户端运行时发生的事情(如套接字或文件错误).我使用的几乎所有其他东西都断言.

另外,如果我要抛出一个断言,那么抛出一个很好的标准对象是什么?IIRC有std :: logic_error但是这不是一个好的对象吗?我会丢失文件或意外输入(例如从命令行而不是前端应用程序)?

c++ exception throw

42
推荐指数
4
解决办法
4万
查看次数

C#中的"按合同设计"

我想在我最新的C#应用​​程序中通过契约尝试一点设计,并希望语法类似于:

public string Foo()
{
    set {
        Assert.IsNotNull(value);
        Assert.IsTrue(value.Contains("bar"));
        _foo = value;
    }
}
Run Code Online (Sandbox Code Playgroud)

我知道我可以从单元测试框架中获取这样的静态方法,但是我想知道这样的东西是否已经内置于该语言中,或者是否已经存在某种类型的框架.我可以编写自己的Assert函数,只是不想重新发明轮子.

c# design-by-contract

37
推荐指数
4
解决办法
2万
查看次数

如何在构造函数中处理不正确的值?

请注意,这是一个关于构造函数的问题,而不是关于处理时间的类.

假设我有一个这样的类:

class Time
{
protected:
    unsigned int m_hour;
    unsigned int m_minute;
    unsigned int m_second;
public:
    Time(unsigned int hour, unsigned int minute, unsigned int second);
};
Run Code Online (Sandbox Code Playgroud)

虽然我希望成功构建一个,但我希望b的构造函数失败.

Time a = Time(12,34,56);
Time b = Time(12,34,65); // second is larger than 60
Run Code Online (Sandbox Code Playgroud)

但是,这是不可能的,因为构造函数不返回任何值,并且总是会成功.

构造函数如何告诉程序它不满意?我想到了几个方法:

  1. 让构造函数抛出异常,并在调用函数中有处理程序来处理它.
  2. 在类中有一个标志,只有当构造函数接受这些值时才将其设置为true,并让程序在构造后立即检查标志.
  3. 有一个单独的(可能是静态的)函数来调用在调用构造函数之前立即检查输入参数.
  4. 重新设计类,以便可以从任何输入参数构造它.

哪种方法在工业中最常见?或者有什么我可能错过的?

c++ error-handling constructor return-value

23
推荐指数
5
解决办法
9256
查看次数

断言总是坏的吗?

我曾经在一家公司工作,其中一些主要架构师/开发人员已经强制要求断言不使用的各种项目,并且他们通常会从代码中删除并替换为异常.

我觉得他们在编写正确的代码时非常重要.任何人都可以建议如何证明这样的授权是合理的吗?如果是这样,断言有什么问题?

c++ exception assertions

20
推荐指数
3
解决办法
4016
查看次数

Debug.Assert vs Exceptions

令人惊讶的我才能够找到SO关于这个主题的一个先前的问题,我只是想获得社会"信任投票"(或不!)我的做法.

我这样看是这样的:

  • Debug.Assert你的处置将是真实的状态的事情.当我们完全控制我们的环境时,例如在验证某些前后条件的方法中,将使用此方法.
  • 在出现特殊情况时使用例外情况.处理外部资源,即文件,数据库,网络等是很容易的.但...

在以下场景中它有点模糊.请注意,这是一个仅供参考的示例!

假设我们有MyClass类,它有一个公共属性MyMode和一个方法GetSomeValueForCurrentMode().将MyClass视为一个打算在库中发布(发布版本)以供其他开发人员使用的版本.

我们希望MyMode可以由此类的外部用户更新.现在,GetSomeValueForCurrentMode()有以下逻辑:

switch(MyMode)
{
case Mode.ModeA:
return val1;
case Mode.ModeB:
return val2;
default:
//Uh-uh this should never happen

}
Run Code Online (Sandbox Code Playgroud)

我在这里得到的是MyClass的用户将其置于无效状态.那我们该怎么办?

在默认情况下,我们应该Debug.Assertthrow new InvalidOperationException(或其他)?

有一句咒语说我们不应该信任我们班级的用户.如果我们选择Debug.Assert并将MyClass构建为发布版本(从而删除Debug Asserts),则该类的用户将无法获得他们将其置于无效状态的有用信息.但这与其他咒语相反,后者只表示在完全无法控制的事情发生时抛出异常.

我发现我围绕着这个问题 - 其中一个编程辩论似乎没有明确的'正确'答案.那么让我们投票吧!

编辑:我在相关的SO问题(使用断言或例外的合同设计?)中注意到了这个响应:

经验法则是,在尝试捕获自己的错误时应使用断言,在尝试捕获其他人的错误时应使用异常.换句话说,您应该使用异常来检查公共API函数的前提条件,以及何时获得系统外部的任何数据.您应该将断言用于系统内部的函数或数据.

对我而言,这是有道理的,并且可以与下面概述的'Assert then throw'技术结合使用.

欢迎思考!

.net exception assertions

17
推荐指数
3
解决办法
3648
查看次数

测试用例和断言陈述

这个问题的代码让我思考

assert(value>0); //Precondition
if (value>0)
{
  //Doit
}
Run Code Online (Sandbox Code Playgroud)

我从不写if语句.断言就足够/你可以做的一切."早点崩溃,经常崩溃"

CodeComplete说明:

  • assert语句使应用程序正确
  • if-test使应用程序更健壮

我不认为您通过更正无效输入值或跳过代码使应用程序更加健壮:

assert(value >= 0 );  //Precondition
assert(value <= 90);  //Precondition
if(value < 0)         //Just in case
  value = 0;
if (value > 90)       //Just in case
  value = 90;
//Doit
Run Code Online (Sandbox Code Playgroud)

这些更正是基于您对外部世界的假设.只有调用者知道你的函数的"有效输入值"是什么,并且他必须在调用你的函数之前检查它的有效性.

CodeComplete来解释:" 当我们依赖于断言时,真实世界的程序会变得太乱."

问题:我错了,顽固,愚蠢,太不防守......

defensive-programming

12
推荐指数
1
解决办法
1355
查看次数

如何验证对象的内部状态?

我很想听听您在操作过程中使用什么技术来验证对象的内部状态,从它自己的角度来看,只能因为内部状态不良或不变违规而失败.

我主要关注的是C++,因为在C#中官方和流行的方式是抛出一个异常,并在C++中有不只是一个单一的方式做到这一点(OK,不是真的在C#或者,我知道).

请注意,我不是在讨论函数参数验证,而是更像是类不变完整性检查.

例如,假设我们想要一个异步打印作业的Printer对象Queue.对于用户来说Printer,该操作只能成功,因为异步队列的结果会在另一时间到达.因此,没有相关的错误代码传达给调用者.

但是对于该Printer对象,如果内部状态不好,则该操作可能会失败,即类不变被破坏,这基本上意味着:一个错误.该条件不一定是Printer对象的用户感兴趣的.

就个人而言,我倾向于混合三种内部状态验证方式,我无法确定哪一个是最好的,如果有的话,哪一个绝对是最差的.我想听听你对这些问题的看法,以及你在这个问题上分享你自己的经验和想法.

我使用的第一种风格 - 以可控制的方式比损坏的数据更好地失败:

void Printer::Queue(const PrintJob& job)
{
    // Validate the state in both release and debug builds.
    // Never proceed with the queuing in a bad state.
    if(!IsValidState())
    {
        throw InvalidOperationException();
    }

    // Continue with queuing, parameter checking, etc.
    // Internal state is guaranteed to be good.
}
Run Code Online (Sandbox Code Playgroud)

我使用的第二种风格 - 比腐败数据更难以控制崩溃:

void Printer::Queue(const PrintJob& job)
{
    // Validate the …
Run Code Online (Sandbox Code Playgroud)

c# c++ validation invariants

7
推荐指数
2
解决办法
2279
查看次数