有一个讨论,在comp.lang.c超过回事++.关于缓和与否的断言,这在C++中默认情况下只在调试中存在的构建,应保持在生产代码或没有.
显然,每个项目都是独特的,所以在这里我的问题是没有这么多是否断言应该保持,但在这情况下,这是值得推荐的/不是一个好主意.
通过断言,我的意思是:
我不一定在谈论C或C++.
我自己的观点是,如果你是程序员,但不拥有数据(大多数商业桌面应用程序就是这种情况),你应该保持它们,因为失败的断言显示了一个错误,你不应该去有bug,有可能破坏用户的数据.这会强制您在发货前进行强力测试,并使错误更加明显,从而更容易发现并修复.
你有什么看法/经验?
干杯,
卡尔
在此查看相关问题
回应和更新
嘿格雷厄姆,
断言是错误的,纯粹而简单,因此应该像一个一样处理.由于应该在发布模式下处理错误,因此您不需要断言.
这就是为什么我在谈论断言时更喜欢"bug"这个词.它使事情更加清晰.对我来说,"错误"这个词太模糊了.丢失的文件是错误,而不是错误,程序应该处理它.试图取消引用空指针是一个错误,程序应该承认有些东西闻起来像坏奶酪.
因此,您应该使用断言来测试指针,但是存在具有正常错误处理代码的文件.
稍微偏离主题,但讨论中的一个重点.
作为一个单挑,如果你的断言在失败时闯入调试器,为什么不呢.但是有很多原因导致文件不存在,完全不受代码控制:读/写权限,磁盘已满,USB设备已拔下等等.由于您无法控制它,我觉得断言是不是处理这个问题的正确方法.
卡尔
托马斯,
是的,我有代码完成,并且必须说我非常不同意该特定建议.
假设您的自定义内存分配器搞砸了,并将一些仍然被其他对象使用的内存归零.我碰巧将这个对象定期解除引用的指针归零,并且其中一个不变量是该指针永远不为空,并且你有几个断言以确保它保持这种状态.如果指针突然为空,你会怎么做?你只是if()围绕它,希望它有效吗?
请记住,我们在这里讨论产品代码,因此不会破坏调试器并检查本地状态.这是用户机器上的一个真正的错误.
卡尔
C++中的插件系统很难,因为ABI没有正确定义,每个编译器(或其版本)都遵循自己的规则.但是,Windows上的COM表明,可以创建一个最小的插件系统,允许具有不同编译器的程序员使用简单的界面为主机应用程序创建插件.
让我们变得实用,并且在这方面保留C++标准,除了一分钟之外.如果我想为支持C++插件的Windows和Mac(以及可选的Linux)编写应用程序,并且我想为插件作者提供相当多的编译器选择(比如说不到2年的Visual C++版本) ,GCC或英特尔的C++编译器),我可以依靠C++的哪些特性?
当然,我认为插件是针对特定平台编写的.
在我的脑海中,这里有一些我能想到的C++特性,我认为答案是:
我很感激您在该领域的任何经验,您可以分享.如果您知道任何具有C++插件系统的中等成功应用程序,那也很酷.
卡尔
我最近阅读了Dan Grossman 撰写的优秀文章" 交易记忆/垃圾收集类比 ".一句话引起了我的注意:
理论上,垃圾收集可以通过增加空间局部性(由于对象重定位)来提高性能,但在实践中,我们为软件工程优势支付适度的性能成本.
在那之前,我的感觉一直都很模糊.一遍又一遍,你会看到GC 可以更高效的说法,所以我总是把这个概念放在脑后.然而,在读完之后,我开始怀疑.
作为衡量对GC语言影响的实验,有些人采用了一些Java程序,跟踪执行,然后用显式内存管理替换了垃圾收集.根据对Lambda最终文章的评论,他们发现GC总是较慢.虚拟内存问题使GC看起来更糟糕,因为收集器在此时经常触及比程序本身更多的内存页,因此导致大量交换.
这对我来说都是实验性的.有没有人,尤其是在C++环境中,在与显式内存管理进行比较时,是否对GC性能进行了全面的基准测试?
特别有趣的是比较各种大型开源项目如何在有或没有GC的情况下执行.以前有人听说过这样的结果吗?
编辑:请关注性能问题,而不是为什么GC存在或为什么它有益.
干杯,
卡尔
PS.如果你已经拔出了火焰喷射器:我并没有试图取消GC的资格,我只是试图找到性能问题的明确答案.
在编译C++代码时,GCC是否会尝试通过选择未标记inline
关键字的内联函数来优化速度?
我试图将类中的成员函数传递给一个带有成员函数类指针的函数.我遇到的问题是我不确定如何使用this指针在类中正确执行此操作.有没有人有建议?
这是传递成员函数的类的副本:
class testMenu : public MenuScreen{
public:
bool draw;
MenuButton<testMenu> x;
testMenu():MenuScreen("testMenu"){
x.SetButton(100,100,TEXT("buttonNormal.png"),TEXT("buttonHover.png"),TEXT("buttonPressed.png"),100,40,&this->test2);
draw = false;
}
void test2(){
draw = true;
}
};
Run Code Online (Sandbox Code Playgroud)
函数x.SetButton(...)包含在另一个类中,其中"object"是模板.
void SetButton(int xPos, int yPos, LPCWSTR normalFilePath, LPCWSTR hoverFilePath, LPCWSTR pressedFilePath, int Width, int Height, void (object::*ButtonFunc)()) {
BUTTON::SetButton(xPos, yPos, normalFilePath, hoverFilePath, pressedFilePath, Width, Height);
this->ButtonFunc = &ButtonFunc;
}
Run Code Online (Sandbox Code Playgroud)
如果有人对如何正确发送此功能有任何建议,以便我以后可以使用它.
Python最强大的一点是易于编写C和C++扩展,以加速处理器密集型代码部分.这些扩展可以避免全局解释器锁定还是受GIL限制?如果没有,那么这种"易于扩展"甚至比我之前意识到的更具杀伤力.我怀疑答案不是简单的是或否,但我不确定,所以我在StackOverflow上问这个问题.
我有一个Makefile,它在应用构建规则之前运行工具开始(这个工具为我写的).如果这个工具是一个python脚本,以非空状态代码退出,我希望GNU Make在那里停止,而不是继续构建程序.
目前,我做这样的事情(顶级,即第1列):
$(info Generating build rules...)
$(shell python collect_sources.py)
include BuildRules.mk
Run Code Online (Sandbox Code Playgroud)
但是如果collect_sources.py
退出时状态代码为1,则不会停止make .这也会捕获标准输出collect_sources.py
但不打印出来,所以我感觉我看错了方向.
如果可能的话,解决方案甚至应该在简单的MS-DOS shell是标准系统shell时工作.
有什么建议吗?
我正在尝试获取指向特定版本的重载成员函数的指针.这是一个例子:
class C
{
bool f(int) { ... }
bool f(double) { ... }
bool example()
{
// I want to get the "double" version.
typedef bool (C::*MemberFunctionType)(double);
MemberFunctionType pointer = &C::f; // <- Visual C++ complains
}
};
Run Code Online (Sandbox Code Playgroud)
错误消息是"错误C2440:'初始化':无法从'重载函数'转换为'MemberFunctionType'"
如果f
没有重载,这可以工作,但不是在上面的例子中.有什么建议吗?
请注意,上面的代码并没有反映我的现实世界问题,那就是我忘记了一个"const" - 这就是被接受的答案所指出的.不过,我会留下问题,因为我觉得问题可能发生在其他人身上.
类层次结构的一个常见错误是将基类中的方法指定为虚拟,以便继承链中的所有重写都能完成某些工作,并且忘记将调用传播到基本实现.
class Container
{
public:
virtual void PrepareForInsertion(ObjectToInsert* pObject)
{
// Nothing to do here
}
};
class SpecializedContainer : public Container
{
protected:
virtual void PrepareForInsertion(ObjectToInsert* pObject)
{
// Set some property of pObject and pass on.
Container::PrepareForInsertion(pObject);
}
};
class MoreSpecializedContainer : public SpecializedContainer
{
protected:
virtual void PrepareForInsertion(ObjectToInsert* pObject)
{
// Oops, forgot to propagate!
}
};
Run Code Online (Sandbox Code Playgroud)
我的问题是:是否有一种好的方法/模式来确保在调用链的末尾始终调用基本实现?
我知道有两种方法可以做到这一点.
您可以使用成员变量作为标志,将其设置为虚方法的基本实现中的正确值,并在调用后检查其值.这需要使用公共非虚方法作为客户端的接口,并使虚方法受到保护(这实际上是一件好事),但它需要专门为此目的使用成员变量(需要如果虚方法必须是const,则是可变的.
class Container
{
public:
void PrepareForInsertion(ObjectToInsert* pObject)
{
m_callChainCorrect = false;
PrepareForInsertionImpl(pObject); …
Run Code Online (Sandbox Code Playgroud)