标签: cpp-core-guidelines

什么是"跨度",什么时候应该使用?

最近我有建议span<T>在我的代码中使用's,或者在网站上看到了一些使用span's - 应该是某种容器的答案.但是 - 我在C++标准库中找不到类似的东西.

那么这个神秘的是什么span<T>,以及为什么(或什么时候)使用它是一个好主意,如果它是非标准的?

c++ c++-faq cpp-core-guidelines c++20 std-span

202
推荐指数
3
解决办法
4万
查看次数

gsl库中span和array_view的区别是什么?

在最近的几次会议演示中,我听说Bjarne Stroustrup和其他人提到了C++的新编码指南以及支持它们的一些类型.

具体来说,我记得一个例子,span<T>而不是(T* p, int n)作为一个函数的参数(在约32:00进入谈话时); 但我也记得使用的建议array_view<T>.它们是两个替代方案但是相同的概念吗?或者我是否混淆了事情,他们实际上并没有那么相关?

我似乎无法找到任何关于它们应该是什么的权威定义.

c++ array-view cpp-core-guidelines guideline-support-library

85
推荐指数
3
解决办法
2万
查看次数

gsl :: not_null <T*>与std :: reference_wrapper <T>对比T&

最近提出了C++核心指南(恭喜!),我担心gsl::not_null类型.如I.12中所述:声明一个不能为null的指针not_null:

帮助避免解除引用nullptr错误.通过避免对nullptr进行冗余检查来提高性能.

...

通过声明源代码中的意图,实现者和工具可以提供更好的诊断,例如通过静态分析查找某些类错误,并执行优化,例如删除分支和空测试.

目的很明确.但是,我们已经有了语言功能.不能为null的指针称为引用.虽然引用一旦创建就无法反弹,但这个问题可以解决std::reference_wrapper.

gsl::not_null和之间的主要区别在于,std::reference_wrapper后者只能用于代替指针,而前者适用于任何事物 - 可nullptr分配(引自 F.17:使用not_null来表示"null"不是有效值):

not_null不只是内置指针.它的工作原理为 array_view,string_view,unique_ptr,shared_ptr,和其他类似指针的类型.

我想象功能比较表如下:

T&:

  • 不能存储nullptr?- 是的
  • Rebindable?-
  • 可以用来代替指针以外的东西吗?-

std::reference_wrapper<T>:

  • 不能存储nullptr?- 是的
  • Rebindable?- 是的
  • 可以用来代替指针以外的东西吗?-

gsl::not_null<T*>:

  • 不能存储nullptr?- 是的
  • Rebindable?- 是的
  • 可以用来代替指针以外的东西吗?- 是的

现在这里是问题,最后:

  1. 我对这些概念之间的差异的理解是否正确?
  2. 这是否意味着std::reference_wrapper现在没用了?

PS我创建了标签cpp-core-guidelines,guideline-support-library为此,我希望正确.

c++ pointers cpp-core-guidelines guideline-support-library

49
推荐指数
2
解决办法
9402
查看次数

C++中类型的单位

C++ Core Guidlines P.1 change_speed示例中,它显示了一个Speed使用的类型,如下所示:

change_speed(Speed s); // better: the meaning of s is specified
// ...
change_speed(2.3); // error: no unit
change_speed(23m / 10s); // meters per second
Run Code Online (Sandbox Code Playgroud)

我对这个例子的最后两行特别感兴趣.第一个似乎暗示如果你没有提供带有参数的单位change_speed就会抛出一个错误.最后一行显示使用一些ms文字定义的单位.现代版C++中是否都有这些新功能?如果是这样,将如何实现这样的东西,以及需要什么版本的C++?

c++ cpp-core-guidelines

17
推荐指数
1
解决办法
1981
查看次数

CppCoreGuidelines C.21是否正确?

在阅读Bjarne Stroustrup的CoreCppGuidelines时,我找到了一条与我的经历相矛盾的指南.

C.21要求如下:

如果您定义或=delete任何默认操作,请定义或=delete全部

原因如下:

特殊函数的语义密切相关,因此如果需要非默认函数,则其他人也需要修改.

根据我的经验,重新定义默认操作的两种最常见情况如下:

#1:使用默认主体定义虚拟析构函数以允许继承:

class C1
{
...
    virtual ~C1() = default;
}
Run Code Online (Sandbox Code Playgroud)

#2:默认构造函数的定义,对RAII类型的成员进行一些初始化:

class C2
{
public:
    int a; float b; std::string c; std::unique_ptr<int> x;

    C2() : a(0), b(1), c("2"), x(std::make_unique<int>(5))
    {}
}
Run Code Online (Sandbox Code Playgroud)

根据我的经验,所有其他情况都很少见.

您如何看待这些例子?它们是C.21规则的例外,还是最好在这里定义所有默认操作?还有其他常见的例外吗?

c++ oop c++11 cpp-core-guidelines

13
推荐指数
2
解决办法
895
查看次数

Cpp核心指南在这个例子中浪费了什么?

Cpp核心指南中的例子浪费了什么?

P.9:不要浪费时间或空间

[...]

void lower(zstring s)
{
    for (int i = 0; i < strlen(s); ++i) s[i] = tolower(s[i]);
}
Run Code Online (Sandbox Code Playgroud)

是的,这是生产代码中的一个例子.我们留给读者来弄清楚浪费了什么.

来自https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rp-waste

c++ cpp-core-guidelines

11
推荐指数
4
解决办法
2022
查看次数

静态成员变量的 C++ 核心指南

我的类中有一个私有静态向量,它保存一个指向所有从它创建的对象的指针。这是必要的,因为每个对象都需要访问来自所有其他对象的信息来执行一些计算:

// Header file:
class Example {
public:
    Example();
private:
    static std::vector<const Example*> examples_;
};
// Cpp file:
std::vector<const Example *> Example::examples_ = {};
Example::Example() {
    // intialization
    examples_.emplace_back(this);
}
void Example::DoCalc() {
    for (auto example : examples_) {
        // do stuff
    }
}
Run Code Online (Sandbox Code Playgroud)

clang-tidy指出我违反了 C++ 核心指南,即:“变量 'examples_' 是非常量且全局可访问的,考虑将其设置为常量(cppcoreguidelines-avoid-non-const-global-variables)”。

就我个人而言,我没有看到我的代码与核心指南中的示例代码之间的相似之处,尤其是因为该变量在一个类中并且是私有的。实现此功能的“正确”方式是什么?如果可以避免,我不想从 clang-tidy 禁用此检查。

c++ static-members cpp-core-guidelines clang-tidy

10
推荐指数
2
解决办法
747
查看次数

为什么我不能用括号括起的初始化列表构造gsl :: span

根据C++核心指南,我应该使用gsl :: span来传递半开序列.

我认为这意味着不要像以下那样编写函数:

void func(const std::vector<int>& data) {
    for (auto v : data) std::cout << v << " ";
}
Run Code Online (Sandbox Code Playgroud)

我更喜欢:

void func(gsl::span<const int> data) {
    for (auto v : data) std::cout << v << " ";
}
Run Code Online (Sandbox Code Playgroud)

其优点在于它不会假定调用者将数据放入a中vector,或强制他们构造临时数据vector.他们可以通过一个std::array例子.

但一个常见的用例是传递一个括号括起来的初始化列表:

func({0,1,2,3})
Run Code Online (Sandbox Code Playgroud)

这适用于一个功能,std::vector但是为了一个功能,gsl::span我得到了错误信息:

错误C2664:'void func(gsl :: span)':无法将参数1从'initializer-list'转换为'gsl :: span'

它看起来像gsl::span 一个模板化的构造函数,旨在采取任何容器.

这只是Microsoft GSL实现中缺少的东西还是有充分理由阻止这种做法?

c++ c++11 cpp-core-guidelines

8
推荐指数
1
解决办法
2713
查看次数

如何使用 C++ Expects 运算符?

我正在使用 C++ 开始一个项目,我之前在少数学校项目之外从未使用过它 - 远不及我现在正在处理的范围。

我的目标是在我努力避免错误、提高性能以及最重要的是:提高代码的可维护性时,尽我最大的努力遵循C++ 核心指南

我已经遇到了数百个问题,从我的 g++/Clang++ 版本不正确到标准库没有被发现到 g++ 使用错误版本的 C++ 编译到非常基本的函数没有按预期运行 -而我没有甚至开始研究 autotools,所以我预计会有更多的麻烦。

不过,这个问题特定于 C++ 核心指南的一部分。接口 6:优先使用 Expects() 来表达前提条件

我尝试编写以下简单代码:

#include <iostream>

using namespace std;

int square(int x) {
    Expects(x > 0);
    return x * x;
}

int main() {
    cout << square(3) << endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这在 g++ 中引发了一个错误:

$> g++ -std=c++17 main.cpp
main.cpp: In function ‘int square(int)’:
main.cpp:7:2: error: ‘Expects’ was not declared in this scope
  Expects(x …
Run Code Online (Sandbox Code Playgroud)

c++ cpp-core-guidelines c++17

8
推荐指数
1
解决办法
8157
查看次数

为什么 not_null 还没有进入 C++ 标准?

"// not null"在第 N 次将注释添加到原始指针后,我再次想知道not_null模板发生了什么。

C++ 核心指南是在很久以前创建的,并且一些内容已经纳入标准,例如std::span(有些内容类似于string_view核心std::array指南本身并且起源于核心指南本身,但有时会被混淆)。鉴于其相对简单,为什么 not_null (或类似的东西)还没有将其纳入标准?

我定期扫描 ISO 邮件(但可能不彻底),而且我什至不知道有这样的建议。


可能回答我自己的问题。我不记得遇到过任何可以防止我编写的代码出现错误的情况,因为我们尽量不以这种方式编写代码。

这些指南本身很受欢迎,例如 clang-tidy 和声纳。支持库似乎不太受欢迎。

例如,boost 从一开始就作为 Linux 上的软件包提供。我不知道 GSL 有任何实现。不过,我认为它与 Windows 上的 Visual C++ 捆绑在一起。


既然评论里有人问了。

我自己会用它来记录意图。像这样的构造not_null<>可能具有注释所没有的语义价值。尽管我可以看到它的位置,但执行它是次要的。这最好以零开销来完成(也许仅在有限数量的情况下在编译时)。

我主要考虑的是原始指针成员变量的情况。我忘记了将指针传递给函数的情况,对于该函数,我总是使用引用来表示非空,也表示“我不取得所有权”。

同样(对于班级成员)我们也可以记录所有权owned<> not_owned<>

我想还有是否允许更改关联对象。但这可能太高了。您可以使用引用成员而不是指针来记录这一点。我自己避免引用成员,因为我几乎总是想要可复制和可分配的类型。但是,请参见示例:我应该在成员数据中选择指针还是引用?对此进行一些讨论。

另一个维度是另一个实体是否可以修改变量。“const”表示我保证不修改它。在多线程代码中,我们想说的几乎相反。那就是“其他代码承诺在我们使用它时不会修改它”(没有显式锁定),但这远离主题......

c++ cpp-core-guidelines

8
推荐指数
1
解决办法
2440
查看次数