在我的C++ JSON库中,我最近使用GCC7进行了回归.我删除了受影响的代码,希望了解错误.
考虑这个标题myclass.hpp:
#pragma once
template <typename X>
struct A
{
struct value_t
{
X array;
};
static A array()
{
return A();
}
friend bool operator<(const A& lhs, const A& rhs) noexcept
{
return lhs.val.array < rhs.val.array;
}
value_t val = {};
};
Run Code Online (Sandbox Code Playgroud)
如您所见,我在struct中使用名称"array"作为成员变量名称value_t,作为静态函数的名称.然后我在以下文件中包含标题:
#include <array>
using std::array; // note this!
#include "myclass.hpp"
int main()
{}
Run Code Online (Sandbox Code Playgroud)
代码用GCC6和Clang5(使用-std=c++11)编译,但GCC7报告:
In file included from example.cpp:3:0:
myclass.hpp: In function 'bool operator<(const …Run Code Online (Sandbox Code Playgroud) 我采取一个类,我希望让用户选择字符串类型(std::string,std::wstring,std::u16string通过模板参数,...).我目前无法使字符串文字符合所选的字符串类型:一旦我决定使用文字前缀("hello"vs. L"hello"vs. u"hello"vs. U"hello"),我会收到所有不兼容字符串类的编译错误.
作为示例,请考虑以下代码(编译--std=c++11):
#include <string>
template<typename StringType>
void hello_string()
{
StringType result("hello");
}
int main()
{
// works
hello_string<std::string>();
hello_string<std::basic_string<char>>();
// the code below does not compile
hello_string<std::wstring>();
hello_string<std::basic_string<unsigned char>>();
hello_string<std::u16string>();
}
Run Code Online (Sandbox Code Playgroud)
函数hello_string()显示了我想要做的事情的本质:将字符串类型作为模板参数,并将字符串文字分配给此类型的变量.
克服我的问题的一种方法是实现该hello_string()函数的几个特化.问题是,这将导致每个字符串文字的几个副本 - 每个字符串文字前缀一个.我认为这是相当丑陋的,必须有更好的方法.
另一种方法是选择"普通"字符串文字作为默认值,并让函数转换为不同的字符串类型.虽然这可以避免代码重复,但它会引入实际上不变的不必要的转换.
我有一个相当大的C++ 库测试套件,行覆盖率接近 100%,但分支覆盖率只有 55.3%。浏览 的结果lcov,似乎大多数错过的分支都可以用 C++ 的多种抛出方法来解释std::bad_alloc,例如每当std::string构造 an 时。
我问自己在这种情况下如何提高分支覆盖率,并认为如果有一个new操作符可以配置std::bad_alloc为在命中测试套件中错过的每个分支所需的分配数量后抛出,那就太好了。
我(天真地)尝试定义一个全局void* operator new (std::size_t)函数,该函数对全局进行倒计时并在到达时int allowed_allocs抛出异常。std::bad_alloc0
但这有几个问题:
new在“第一次”需要之前很难获得呼叫数量throw。我可以执行试运行来计算成功所需的调用,但是如果多个调用可能在同一行中失败,则这无济于事,例如,类似于std::to_string(some_int) + std::to_string(another_int)where every std::to_string、串联 viaoperator+以及初始分配可能会失败。new调用,因此即使我知道我的代码需要多少次调用,也很难猜测测试套件需要多少次额外调用。(更糟糕的是,Catch 有几种“详细”模式,它们会创建大量输出,而这些输出又需要内存......)您知道如何提高分支机构覆盖率吗?
同时,我发现/sf/answers/3060836831/包含一个 Python 脚本的链接,用于过滤 lcov 输出中的异常创建的一些分支。这使我的分支覆盖率达到了 71.5%,但是剩下的未命中的分支仍然很奇怪。例如,我有几个这样的 if 语句:
有四个 (?) 分支,其中一个分支未被击中 (reference_token是 a std::string)。
有谁知道这些分支意味着什么以及如何攻击它们?
我实现了一个JSON解析器并提供了一个operator>>从一个解析的函数std::ifstream.为了加快读取速度,我将16 KB复制到一个缓冲区中,让我的解析器从缓冲区中读取.一个小的基准测试显示,这比直接使用std::ifstream::get或更快std::ifstream::read.
当我成功读取JSON值时,我想将所有不需要的字节从缓冲区"放回"到流中,因此随后的调用operator>>将std::istream继续解析第一个调用结束的位置.我目前正在实施这样的"退回":
is.clear();
is.seekg(start_position + static_cast<std::streamoff>(processed_chars));
is.clear();
Run Code Online (Sandbox Code Playgroud)
因此,is输入文件流start_position是解析器读取的字符的初始值is.tellg()和processed_chars字符数.
这适用于GCC和Clang与OSX和Linux,但MSVC 2015和MSVC 2017无法将输入流带入所需状态.
显然,我在这里做错了什么.不同的编译器不应该表现得如此不同.该clear()电话已经尝试错误的结果,以与GCC/Clang的代码的运行.
什么是正确的方法(a)从已经打开std::ifstream使用缓存读取和(b)能够在最后处理的字符之后(而不是在最后一个缓存的字符之后)恢复解析?
有没有更好的方法快速阅读已经开放的std::ifstream?如上所述,删除缓存会使解析器变慢.
(对于天真的问题和可怕的实现道歉!我没有找到一个答案,处理已经打开std::ifstream或可以"放回"已经缓存的字符.)
我们正在研究一种模型检查工具,它可以执行几十亿次搜索程序.我们有不同的搜索例程,目前使用预处理器指令进行选择.这不仅非常不方便,因为我们每次做出不同的选择时都需要重新编译,但也使代码难以阅读.现在是开始新版本的时候了,我们正在评估是否可以避免条件编译.
这是一个非常人为的例子,显示了效果:
/* program_define */
#include <stdio.h>
#include <stdlib.h>
#define skip 10
int main(int argc, char** argv) {
int i, j;
long result = 0;
int limit = atoi(argv[1]);
for (i = 0; i < 10000000; ++i) {
for (j = 0; j < limit; ++j) {
if (i + j % skip == 0) {
continue;
}
result += i + j;
}
}
printf("%lu\n", result);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这里,变量skip是影响程序行为的值的示例.不幸的是,我们需要在每次需要新值时重新编译skip.
让我们看看该程序的另一个版本:
/* program_variable */
#include …Run Code Online (Sandbox Code Playgroud)