我喜欢在c ++中使用sentry类,但我似乎有一种精神上的痛苦,导致反复编写如下错误:
{
MySentryClass(arg);
// ... other code
}
毋庸置疑,这是失败的,因为哨兵在创作后立即死亡,而不是按照预期在范围的最后。有没有办法阻止MySentryClass被实例化为临时代码,以便上面的代码无法编译,或者至少在运行时中止错误消息?
答案 0 :(得分:8)
我无法想到一种自动检测你是否犯这个错误的方法。您可以随时创建一个扩展为正确的宏,并使用它来声明哨兵,如果您继续使用错误。
#define MY_SENTRY_CLASS(_X) MySentryClass _sentry(_X)
然后使用
MY_SENTRY_CLASS(arg);
或在显示器上贴一张贴子以提醒您。
答案 1 :(得分:4)
您唯一能做的就是将构造函数设为私有,并通过辅助函数强制访问。这远比初始构造语法更不相似,也不太可能被误解。你也可以在堆上分配(仍然是一种浪费),但它更容易被发现。但是,如果你希望你的类是可构造的,你就不能阻止人们构造那种类型的rvalues。
编辑:如果你知道MySentryClass总是接受一个参数,你可以禁止构造AND并且只允许operator =(arguments)。这会迫使你做
MySentryClass x;
x = arg;
你可以为它做一些方法链。
MySentryClass x;
x.SetArg1(arg).SetArg2(arg2).construct();
答案 2 :(得分:3)
不,这个问题没有退出。要在堆栈上创建对象,您必须拥有公共构造函数,如果您有公共构造函数,则可以犯下您正在报告的错误。
答案 3 :(得分:2)
不确定您是否会喜欢此解决方案,但解决方案可能是grep
:
find /path/to/project -type f -name \*.cpp -print0 | xargs grep -0 'MySentryClass('
您可以做的另一件事是使用sed
或perl
预处理您的源文件,将MySentryClass(
替换为\n#error MySentryClass used incorrectly\n
,这有望为您提供一个关闭的行号到错误的地方。如何执行此操作取决于您的构建系统。
答案 4 :(得分:1)
我认为#define是最好的方法 但是作为不使用#define的选项:
int main()
{
try
{
S arg1;
// This will not compile
// MySentry x1 = MySentry::CreateSentry(arg1);
S arg3;
MySentry x2(MySentry::CreateSentry(arg3));
S arg2;
// This will not compile
// MySentry(arg2);
S arg4;
// This will generate a runtime exception
// It will never call start() or end()
//MySentry::CreateSentry(arg4);
}
catch(std::exception const& e)
{
std::cout << "Exception : " << e.what() << "\n";
}
}
#include <stdexcept>
#include <iostream>
class S
{
public:
void start() {std::cout << "Start\n";}
void end() {std::cout << "End\n";}
};
class MySentry
{
struct Init
{
Init(S& s) : arg(s),bad(true) {}
~Init() {if (bad) {throw std::runtime_error("Bad usage of MySentry");}}
S& arg;
mutable bool bad;
};
public:
static Init CreateSentry(S& arg) { return Init(arg);}
explicit MySentry(Init const& arg)
: obj(arg.arg)
, bad(false)
{
arg.bad = false;
std::cout << "Created\n";
obj.start();
}
MySentry(MySentry const& rhs)
: obj(rhs.obj)
, bad(false)
{
std::cout << "Copied (this may not appear)\n";
std::cout << "If the optimizer kicks in then the copy may be elided.\n";
// But if it did not optimize out then
// We have to mark the temporaty as bad
// And not call end() in its destructor.
// Note: Never call start() here as it will always be called in the
// main private constrctor above
rhs.bad = true;
}
~MySentry()
{
if (!bad)
{
// Everything working
obj.end();
}
std::cout << "Destroyed\n";
}
private:
S& obj;
mutable bool bad;
};
答案 5 :(得分:0)
您尝试做的事情在C ++中是完全合法的,我认为没有办法禁止它。