如何 return 来自方法的可选调试信息?
How to return optional debug information from a method?
假设我有一个静态方法,它比较两个对象的接近匹配和 return 一些置信度 [0,1]。
class Foo
{
...
static double Compare(const Foo& foo1, const Foo& foo2);
...
};
现在我需要 return 包含比较详细信息的附加调试信息,具体取决于配置中的设置。
由于此调试信息不会在生产中使用,而仅用于 testing/debugging 目的,我想知道实现它的适当方法是什么。
我看到至少三个选项:
1:创建一个额外的 class CompareResult 并在其中存储置信度 + 可选信息。如果不需要,请不要填充可选信息。
class CompareResult
{
...
private:
double confidence_;
CompareOptionalInfo compare_optional_info_;
...
};
...
static CompareResult Compare(const Foo& foo1, const Foo& foo2);
这似乎是最干净的一个,但我不确定是否应该将 return 结果与可选信息结合起来。
2:使用输出变量(这样我们就不需要创建额外的class,但是我们的方法签名会增长一点)
static double Compare(const Foo& foo1, const Foo& foo2, CompareOptionalInfo* out_compare_info = nullptr);
3: 将比较方法与可选信息检索方法分开。
static double Compare(const Foo& foo1, const Foo& foo2);
static CompareOptionalInfo GetCompareOptionalInfo();
此选项可能需要在方法调用之间存储此可选信息,并从静态比较方法转移到实例比较方法。
但是还是那句话,不知道合适不合适。
根据您的经验,在 OOP 世界中从方法中 return 可选信息(主要仅在调试模式下使用)的适当方式是什么?
我会使用第二个选项,因为它与调试器兼容。
在调试模式下,您可以添加一个额外的静态成员。您应该注意不应抑制它的链接器。
class Foo
{
private:
#ifndef NDEBUG
CompareOptionalInfo debug_out_compare_info_;
#endif
...
static double Compare(const Foo& foo1, const Foo& foo2,
CompareOptionalInfo* out_compare_info = nullptr);
...
};
#ifndef NDEBUG
CompareOptionalInfo Foo::debug_out_compare_info_;
#endif
在gdb中,在任何断点处,您可以使用:
call Foo::Compare(foo1, foo2, &Foo::debug_out_compare_info_);
print Foo::debug_out_compare_info_. ...
选项 3 根本不是一个好主意:具有依赖于静态数据的函数是不切实际的,甚至可能成为调试中错误的来源。这样的设计也不是线程安全的;多么遗憾,创建这样的限制只是为了调试目的!
问题示例:
double closest = std::max (Foo::compare (x, y), Foo::compare (y,z));
clog << Foo::GetCompareOptionalInfo(); // undefined which info since order of eval
// of function parameter is not guaranteed
double d = Foo::compare (x, y);
DoSomething(); // what if this one does an unexpected compare ?
clog << Foo::GetCompareOptionalInfo();
选项 2 是一个可行的解决方案,但它不是很方便:它迫使您创建信息对象,通过地址等传递它们:
Foo::OptionalCompareInfo o1,o2; // cumbersome
double closest = std::max (Foo::compare (x, y, &o1), Foo::compare (y,z, &o2));
此外,您将创建这些可选信息并在生产中传递额外的参数,即使您不再在那里更新信息(除非您放置大量额外的条件编译)!
选项 1 非常好!去吧 !它确实利用了 OOP 范例并使用了简洁的设计。使用起来很实用,不要对您的代码施加限制以使用它。
您所需要的只是提供一些(隐含的)转换函数来使用您的 CompareResult
,就好像它是一个 double
:
class CompareResult
{
public:
CompareResult(double d=0.0) : confidence_(d) {};
operator double() { return confidence_; }
operator bool() { return confidence_>0.5; }
private:
double confidence_;
CompareOptionalInfo compare_optional_info_;
};
您的生产代码将不受调试信息的影响。你可以在调试中始终追溯任何给定比较结果的解释,至少如果你存储它:
示例:
auto result = Foo::compare (x, y)
if (result) ... // uses automatically the conversion
auto closest = std::max (Foo::compare (x, y), Foo::compare (y,z));
// here you not only know the closest match but could explain it !
vector<CompareResult> v;
... // populate the vector with 10 000 comparison results
auto r = std::max_element(v.begin(), v.end());
// you could still explain the compare info for the largest value
// if you're interested in the details of this single value
// how would you do this with option 3 or option 2 ?
好的,要使最后一个工作正常,您还需要一个用于附加 class 的比较运算符。但这还多了一行代码(参见在线演示);-)
最后,事实证明您的 "optional debug info" 可能比预期的更有用,例如根据要求向用户提供额外的解释。然后,您需要做的就是删除围绕可选信息计算的条件 #ifdef DEBUG
。
假设我有一个静态方法,它比较两个对象的接近匹配和 return 一些置信度 [0,1]。
class Foo
{
...
static double Compare(const Foo& foo1, const Foo& foo2);
...
};
现在我需要 return 包含比较详细信息的附加调试信息,具体取决于配置中的设置。 由于此调试信息不会在生产中使用,而仅用于 testing/debugging 目的,我想知道实现它的适当方法是什么。
我看到至少三个选项:
1:创建一个额外的 class CompareResult 并在其中存储置信度 + 可选信息。如果不需要,请不要填充可选信息。
class CompareResult
{
...
private:
double confidence_;
CompareOptionalInfo compare_optional_info_;
...
};
...
static CompareResult Compare(const Foo& foo1, const Foo& foo2);
这似乎是最干净的一个,但我不确定是否应该将 return 结果与可选信息结合起来。
2:使用输出变量(这样我们就不需要创建额外的class,但是我们的方法签名会增长一点)
static double Compare(const Foo& foo1, const Foo& foo2, CompareOptionalInfo* out_compare_info = nullptr);
3: 将比较方法与可选信息检索方法分开。
static double Compare(const Foo& foo1, const Foo& foo2);
static CompareOptionalInfo GetCompareOptionalInfo();
此选项可能需要在方法调用之间存储此可选信息,并从静态比较方法转移到实例比较方法。 但是还是那句话,不知道合适不合适。
根据您的经验,在 OOP 世界中从方法中 return 可选信息(主要仅在调试模式下使用)的适当方式是什么?
我会使用第二个选项,因为它与调试器兼容。
在调试模式下,您可以添加一个额外的静态成员。您应该注意不应抑制它的链接器。
class Foo
{
private:
#ifndef NDEBUG
CompareOptionalInfo debug_out_compare_info_;
#endif
...
static double Compare(const Foo& foo1, const Foo& foo2,
CompareOptionalInfo* out_compare_info = nullptr);
...
};
#ifndef NDEBUG
CompareOptionalInfo Foo::debug_out_compare_info_;
#endif
在gdb中,在任何断点处,您可以使用:
call Foo::Compare(foo1, foo2, &Foo::debug_out_compare_info_);
print Foo::debug_out_compare_info_. ...
选项 3 根本不是一个好主意:具有依赖于静态数据的函数是不切实际的,甚至可能成为调试中错误的来源。这样的设计也不是线程安全的;多么遗憾,创建这样的限制只是为了调试目的!
问题示例:
double closest = std::max (Foo::compare (x, y), Foo::compare (y,z));
clog << Foo::GetCompareOptionalInfo(); // undefined which info since order of eval
// of function parameter is not guaranteed
double d = Foo::compare (x, y);
DoSomething(); // what if this one does an unexpected compare ?
clog << Foo::GetCompareOptionalInfo();
选项 2 是一个可行的解决方案,但它不是很方便:它迫使您创建信息对象,通过地址等传递它们:
Foo::OptionalCompareInfo o1,o2; // cumbersome
double closest = std::max (Foo::compare (x, y, &o1), Foo::compare (y,z, &o2));
此外,您将创建这些可选信息并在生产中传递额外的参数,即使您不再在那里更新信息(除非您放置大量额外的条件编译)!
选项 1 非常好!去吧 !它确实利用了 OOP 范例并使用了简洁的设计。使用起来很实用,不要对您的代码施加限制以使用它。
您所需要的只是提供一些(隐含的)转换函数来使用您的 CompareResult
,就好像它是一个 double
:
class CompareResult
{
public:
CompareResult(double d=0.0) : confidence_(d) {};
operator double() { return confidence_; }
operator bool() { return confidence_>0.5; }
private:
double confidence_;
CompareOptionalInfo compare_optional_info_;
};
您的生产代码将不受调试信息的影响。你可以在调试中始终追溯任何给定比较结果的解释,至少如果你存储它:
示例:
auto result = Foo::compare (x, y)
if (result) ... // uses automatically the conversion
auto closest = std::max (Foo::compare (x, y), Foo::compare (y,z));
// here you not only know the closest match but could explain it !
vector<CompareResult> v;
... // populate the vector with 10 000 comparison results
auto r = std::max_element(v.begin(), v.end());
// you could still explain the compare info for the largest value
// if you're interested in the details of this single value
// how would you do this with option 3 or option 2 ?
好的,要使最后一个工作正常,您还需要一个用于附加 class 的比较运算符。但这还多了一行代码(参见在线演示);-)
最后,事实证明您的 "optional debug info" 可能比预期的更有用,例如根据要求向用户提供额外的解释。然后,您需要做的就是删除围绕可选信息计算的条件 #ifdef DEBUG
。