如何跟踪通话统计?C++
How to keep track of call statistics? C++
我正在做一个向用户提供统计数据的项目。我创建了一个名为 Dog 的类,它有几个功能。说话,哇,跑,取等。
我想要一个函数来吐出每个函数被调用了多少次。我也对构造函数调用和析构函数调用感兴趣。
我有一个定义所有函数的头文件,然后是一个单独的 .cc 文件来实现它们。我的问题是,有没有办法跟踪每个函数被调用的次数?
我有一个名为 print 的函数,它将获取"统计信息",然后将它们输出到标准输出。我正在考虑使用静态整数作为类本身的一部分,声明几个整数来跟踪这些事情。我知道编译器将创建整数的副本并将其初始化为最小值,然后我将递增 .cc 函数中的整数。
我还考虑过将静态整数作为 .cc 中的全局变量。哪种方式更容易?或者有更好的方法可以做到这一点吗?
任何帮助将不胜感激!
使用静态成员变量是要走的路。但是,编译器不会"创建整数的副本并将其初始化为最小值";您必须在 .cc 文件中为每个定义提供一个定义,并在那里将其初始化为 0。(如果您使用的是 C++11,情况会有所不同,但基本思想是相同的。
没有理由使用静态全局变量而不是静态成员。
傅炯:
class Foo {
static int countCtor_;
static int countDtor_;
static int countprint_:
Foo();
~Foo();
static void print();
};
foo.cc:
#include <iostream>
#include "foo.h"
int Foo::countCtor_ = 0;
int Foo::countDtor_ = 0;
int Foo::countprint_ = 0;
Foo::Foo() {
++countCtor_;
// Something here
}
Foo::~Foo() {
++countDtor_;
// Something here
}
void Foo::print() {
++countprint_;
std::cout << "Ctor: " << countCtor_ << "n"
<< "Dtor: " << countDtor_ << "n"
<< "print: " << countprint_ << "n";
}
但是如果你有很多函数,所涉及的重复有点烦人 - 当你的意思是++countBaz_时countBar_,很容易不小心做++所以你可能想要一些更花哨的东西,比如静态映射和一个递增计数的宏[__FUNC__],所以你可以在每个函数中使用完全相同的行。喜欢这个:
傅炯:
#include <map>
class Foo {
static std::map<const char*, int> counts_;
Foo();
~Foo();
void print();
};
foo.cc:
#include <iostream>
#include "foo.h"
std::map<const char *, int> Foo::counts_;
#define INC_COUNT_() do { ++counts_[__FUNC__]; } while (0)
Foo::Foo() {
INC_COUNT_();
// Something here
}
Foo::~Foo() {
INC_COUNT_();
// Something here
}
void Foo::print() {
INC_COUNT_();
for (std::map<const char *, int>::const_iterator it = counts_.begin();
it != counts_.end(); ++it) {
std::cout << it->first << ": " << it->second << "n";
}
}
在上面的示例代码中,__FUNC__是一个占位符。遗憾的是,没有符合标准的值可以在其位置使用。大多数编译器都有一些__func__、__FUNC__、__FUNCTION__、__FUNCSIG__和__PRETTY_FUNCTION__子集。但是,这些都不是 C++03 中的标准配置。C++11 确实标准化了__func__,但仅作为"实现定义的字符串",这不能保证有用,甚至不唯一。最重要的是,不同编译器上的值会有所不同。此外,其中一些可能是宏而不是标识符,以使事情更有趣。
如果你想要真正可移植的代码,在 C++11 中,你可以使用 string(__func__) + ":" + STRINGIZE(__LINE__) 这样的东西——这会有点难看,但至少每个函数都有一个唯一的名称。而在 C++03 中,没有等价物。如果您只需要"足够便携",请查阅您使用的每个编译器的文档,或者依赖 autoconf 之类的东西。
有什么理由不能使用标准分析工具来计算这些调用吗?像 gprof 这样的东西?
否则,静态整数将是要走的路。
假设您希望在程序中始终跟踪这些统计信息,则可以使用函数名称的unordered_map
:
std::unordered_map<const char *, unsigned> stats;
void foo () {
// use __FUNCDNAME__ for MSVC
++stats[__PRETTY_FUNCTION__];
//...
}
使用编译器特定的函数名称说明符是故意获取修饰的函数名称。这样,重载的函数名称就会计为单独的函数。
这种技术允许您轻松添加新函数而无需考虑其他任何事情,但如果存在哈希冲突,则需要支付少量额外费用(可以通过调整stats
映射的大小来弥补)。字符串上没有计算哈希,因为键是指针类型,它只是使用指针值本身作为哈希。
如果这只是用于分析的一次性代码,则应首先尝试使用平台上可用的代码分析工具。
您可以将static
局部变量放入方法本身中,这似乎更干净,因为这些变量在逻辑上没有连接到类,因此没有理由使它们成为成员。
此外,您可以使用宏来简化工作。我通常不建议使用宏,但这似乎是一个合适的用法:
#define DEFINE_COUNTER
static int noCalls = 0;
noCalls++;
void foo()
{
DEFINE_COUNTER
}
使用实现观察者模式或方法调用拦截的库。 您可以从此列表中选择一种,或使用维生素之类的东西。
- 为什么 gcovr 会生成空覆盖率统计信息?
- Qt 错误:QSqlQuery::value:尝试从表中检索统计信息时未定位在有效记录上 (QComboBox)
- 在C++中获取 Linux 网络统计信息
- 字数统计函数在将单词添加到一组唯一单词时遇到问题
- 使用排序C++进行字数统计
- 我想重置一个C++结构统计,我可以以某种方式使用 stat() 语法吗?
- C++字数统计程序使用C字符串错误在程序运行后
- 在 C++ 年的 Linux 中实现对非基于文本的文件作为 wc 的字数统计
- 避免在统计数据和重命名之间进行TOCTOU(检查时间,使用时间)
- 使用多集__gnu_pbds的顺序统计树
- 使用 boost::累加器::统计来查找数组的中位数
- 如何在 Windows 上从 C++11 统计信息对象的文件序列号中查找文件名
- 是否有一些有意义的统计数据来证明保持有符号整数算术溢出未定义是合理的
- Magick++ ImageMagick 7.0.5-4 Q16 的统计数据x86_64问题
- 替换(或重新实现?)std::函数用于某些统计和测试
- C++ 中的统计模拟
- C++的有效字数统计多线程
- PCL 和 CMake 的问题:链接时未定义统计异常值删除
- 在调试中,如何知道对函数的重复调用中参数的统计数据(max-min,average,distribution..)
- ifstream 的意外行为(字数统计)