有一个讨论,在comp.lang.c超过回事++.关于缓和与否的断言,这在C++中默认情况下只在调试中存在的构建,应保持在生产代码或没有.
显然,每个项目都是独特的,所以在这里我的问题是没有这么多是否断言应该保持,但在这情况下,这是值得推荐的/不是一个好主意.
通过断言,我的意思是:
我不一定在谈论C或C++.
我自己的观点是,如果你是程序员,但不拥有数据(大多数商业桌面应用程序就是这种情况),你应该保持它们,因为失败的断言显示了一个错误,你不应该去有bug,有可能破坏用户的数据.这会强制您在发货前进行强力测试,并使错误更加明显,从而更容易发现并修复.
你有什么看法/经验?
干杯,
卡尔
在此查看相关问题
回应和更新
嘿格雷厄姆,
断言是错误的,纯粹而简单,因此应该像一个一样处理.由于应该在发布模式下处理错误,因此您不需要断言.
这就是为什么我在谈论断言时更喜欢"bug"这个词.它使事情更加清晰.对我来说,"错误"这个词太模糊了.丢失的文件是错误,而不是错误,程序应该处理它.试图取消引用空指针是一个错误,程序应该承认有些东西闻起来像坏奶酪.
因此,您应该使用断言来测试指针,但是存在具有正常错误处理代码的文件.
稍微偏离主题,但讨论中的一个重点.
作为一个单挑,如果你的断言在失败时闯入调试器,为什么不呢.但是有很多原因导致文件不存在,完全不受代码控制:读/写权限,磁盘已满,USB设备已拔下等等.由于您无法控制它,我觉得断言是不是处理这个问题的正确方法.
卡尔
托马斯,
是的,我有代码完成,并且必须说我非常不同意该特定建议.
假设您的自定义内存分配器搞砸了,并将一些仍然被其他对象使用的内存归零.我碰巧将这个对象定期解除引用的指针归零,并且其中一个不变量是该指针永远不为空,并且你有几个断言以确保它保持这种状态.如果指针突然为空,你会怎么做?你只是if()围绕它,希望它有效吗?
请记住,我们在这里讨论产品代码,因此不会破坏调试器并检查本地状态.这是用户机器上的一个真正的错误.
卡尔
大多数时候我会使用异常来检查代码中的条件,我想知道什么时候使用断言是合适的时间?
例如,
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异常处理和使用assert条件之间有什么区别?
众所周知,Assert有两种类型.但什么时候应该使用assert关键字?
可能重复:
通过断言或异常的合同测试设计?
在决定使用异常而不是断言时(或反之亦然),是否遵循经验法则.现在我只会抛出我认为会在用户端运行时发生的事情(如套接字或文件错误).我使用的几乎所有其他东西都断言.
另外,如果我要抛出一个断言,那么抛出一个很好的标准对象是什么?IIRC有std :: logic_error但是这不是一个好的对象吗?我会丢失文件或意外输入(例如从命令行而不是前端应用程序)?
我想在我最新的C#应用程序中通过契约尝试一点设计,并希望语法类似于:
public string Foo()
{
set {
Assert.IsNotNull(value);
Assert.IsTrue(value.Contains("bar"));
_foo = value;
}
}
Run Code Online (Sandbox Code Playgroud)
我知道我可以从单元测试框架中获取这样的静态方法,但是我想知道这样的东西是否已经内置于该语言中,或者是否已经存在某种类型的框架.我可以编写自己的Assert函数,只是不想重新发明轮子.
请注意,这是一个关于构造函数的问题,而不是关于处理时间的类.
假设我有一个这样的类:
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)
但是,这是不可能的,因为构造函数不返回任何值,并且总是会成功.
构造函数如何告诉程序它不满意?我想到了几个方法:
哪种方法在工业中最常见?或者有什么我可能错过的?
我曾经在一家公司工作,其中一些主要架构师/开发人员已经强制要求断言不使用的各种项目,并且他们通常会从代码中删除并替换为异常.
我觉得他们在编写正确的代码时非常重要.任何人都可以建议如何证明这样的授权是合理的吗?如果是这样,断言有什么问题?
令人惊讶的我才能够找到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.Assert或throw new InvalidOperationException(或其他)?
有一句咒语说我们不应该信任我们班级的用户.如果我们选择Debug.Assert并将MyClass构建为发布版本(从而删除Debug Asserts),则该类的用户将无法获得他们将其置于无效状态的有用信息.但这与其他咒语相反,后者只表示在完全无法控制的事情发生时抛出异常.
我发现我围绕着这个问题 - 其中一个编程辩论似乎没有明确的'正确'答案.那么让我们投票吧!
编辑:我在相关的SO问题(使用断言或例外的合同设计?)中注意到了这个响应:
经验法则是,在尝试捕获自己的错误时应使用断言,在尝试捕获其他人的错误时应使用异常.换句话说,您应该使用异常来检查公共API函数的前提条件,以及何时获得系统外部的任何数据.您应该将断言用于系统内部的函数或数据.
对我而言,这是有道理的,并且可以与下面概述的'Assert then throw'技术结合使用.
欢迎思考!
这个问题的代码让我思考
assert(value>0); //Precondition
if (value>0)
{
//Doit
}
Run Code Online (Sandbox Code Playgroud)
我从不写if语句.断言就足够/你可以做的一切."早点崩溃,经常崩溃"
CodeComplete说明:
我不认为您通过更正无效输入值或跳过代码使应用程序更加健壮:
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来解释:" 当我们不依赖于断言时,真实世界的程序会变得太乱."
问题:我错了,顽固,愚蠢,太不防守......
我很想听听您在操作过程中使用什么技术来验证对象的内部状态,从它自己的角度来看,只能因为内部状态不良或不变违规而失败.
我主要关注的是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++ ×4
exception ×4
assert ×2
assertions ×2
c# ×2
java ×2
.net ×1
assertion ×1
constructor ×1
invariants ×1
return-value ×1
throw ×1
validation ×1