小编Ete*_*nal的帖子

为什么在C++ 17中使用std :: make_unique?

据我所知,引入了C++ 14 std::make_unique,因为由于没有指定参数评估顺序,这是不安全的:

f(std::unique_ptr<MyClass>(new MyClass(param)), g()); // Syntax A
Run Code Online (Sandbox Code Playgroud)

(说明:如果评估首先为原始指针分配内存,则g()std::unique_ptr构造之前抛出调用和异常,然后内存泄漏.)

呼叫std::make_unique是一种约束呼叫顺序的方法,从而使事情变得安全:

f(std::make_unique<MyClass>(param), g());             // Syntax B
Run Code Online (Sandbox Code Playgroud)

从那以后,C++ 17澄清了评估顺序,使得Syntax A也安全,所以这里是我的问题:在C++ 17中仍然有理由使用std::make_uniqueover std::unique_ptr的构造函数吗?你能举一些例子吗?

截至目前,我能想象的唯一原因是它只允许输入MyClass一次(假设您不需要依赖多态std::unique_ptr<Base>(new Derived(param))).但是,这似乎是一个非常弱的原因,特别是当构造函数std::make_unique不允许指定删除器时std::unique_ptr.

而且为了清楚起见,我并不是主张std::make_unique从标准库中删除(至少为了向后兼容而保持它有意义),而是想知道是否仍然存在强烈倾向于它的情况std::unique_ptr

c++ unique-ptr c++17

86
推荐指数
4
解决办法
6688
查看次数

隐式转换和运算符重载

所以,我写了这样的东西

#include <iostream>
using namespace std;

void f(int32_t i)
{
    cout << "int32: " << i << endl;
}

void f(int16_t i)
{
    cout << "int16: " << i << endl;
}

void f(int8_t i)
{
    cout << "int8: " << i << endl;
}

void f(uint32_t i)
{
    cout << "uint32: " << i << endl;
}

void f(uint16_t i)
{
    cout << "uint16: " << i << endl;
}


int main() {
    uint8_t i = 0u;
    f(i);
    return …
Run Code Online (Sandbox Code Playgroud)

c++ overloading implicit-conversion c++11

17
推荐指数
2
解决办法
859
查看次数

声明constexpr函数或方法

我想知道是否有必要声明constexpr函数和方法的限制,就像内联函数和方法一样.

我知道必须在头文件中编写内联函数或方法,以使编译器能够访问它们被调用的定义.如果constexpr有类似的东西会有意义,但我无法找到关于这一点的任何东西......

基本上我的问题是:

  • 我是否可以在头文件中编写constexpr函数的定义而不会冒重复符号的风险?

  • 我可以分离constexpr函数或方法的声明和定义吗?

c++ constexpr c++11

9
推荐指数
1
解决办法
1581
查看次数

"使用typename"指令是否未由编译器实现?

我有一些看起来像这样的代码:

namespace myLibrary
{
    class A
    {
    public:
        struct Nested
        {
            ...
        };

        ...
    };
}
Run Code Online (Sandbox Code Playgroud)

在代码的其他部分,我需要访问A.因为我喜欢可读的代码,我也喜欢using指令:

using myLibrary::A;
...
A a;
Run Code Online (Sandbox Code Playgroud)

现在,在某些时候我还需要访问我的嵌套类,所以我想写这样的东西:

using myLibrary::A::Nested;
Run Code Online (Sandbox Code Playgroud)

显然,编译器不能知道这是一个嵌套类而不是类成员,并给我一个错误:

error : using declaration can not refer to class member
Run Code Online (Sandbox Code Playgroud)

我无法理解的是为什么这不能解决问题:

using typename myLibrary::A::Nested;
Run Code Online (Sandbox Code Playgroud)

编译器仍然给我完全相同的错误!

幸运的是,我有其他选择:

// Using a typedef
typedef myLibrary::A::Nested Nested;

// Using the new C++11 syntax for type aliasing
using Nested = myLibrary::A::Nested;
Run Code Online (Sandbox Code Playgroud)

但我想了解为什么使用typename指令不起作用.它不符合我的想法吗?或者它不是由编译器实现的?如果是后者,是否有理由呢?

c++ using nested-class typename

7
推荐指数
1
解决办法
3747
查看次数

正确使用通用参考

在c ++ 11之前,我曾经写过这样的代码:

// Small functions
void doThingsWithA(const A& a)
{
    // do stuff
}

void doThingsWithB(const B& b)
{
    // do stuff
}

void doThingsWithC(const C& c)
{
    // do stuff
}

// Big function
void doThingsWithABC(const A& a, const B& b, const C& c)
{
    // do stuff
    doThingsWithA(a);
    doThingsWithB(b);
    doThingsWithC(c);
    // do stuff
}
Run Code Online (Sandbox Code Playgroud)

但是现在,使用移动语义,允许我的函数将rvalue引用作为参数并添加这些重载可能会变得有趣(至少在某些情况下):

void doThingsWithA(A&& a);
void doThingsWithB(B&& b);
void doThingsWithC(C&& c);
Run Code Online (Sandbox Code Playgroud)

从我收集的内容来看,如果我想在我的大函数中调用那些重载,我需要使用完美的转发,这可能看起来像这样(它的可读性稍差,但我想它可以用模板类型的良好命名约定):

template<typename TplA, typename TplB, typename TplC>
void doThingsWithABC(TplA&& a, TplB&& b, TplC&& …
Run Code Online (Sandbox Code Playgroud)

c++ perfect-forwarding c++11 universal-reference forwarding-reference

7
推荐指数
2
解决办法
1557
查看次数

是不是使用统一初始化危险?

几天前我发现了统一初始化,我看到每个人都应该尽可能地使用它.

但是,我不禁想到这种新语法比它的价值更麻烦......


第一个例子

假设我写了一个库,其中我有一个像这样的结构:

struct MyStruct
{
    int member0;
    int member1;
}
Run Code Online (Sandbox Code Playgroud)

用户可以使用聚合初始化来编写类似的东西:

MyStruct myVar = {0, 1}; // member0 = 0 and member1 = 1
Run Code Online (Sandbox Code Playgroud)

现在,让我们说我更新了我的库,结构现在看起来像这样:

struct MyStruct
{
    int member0;
    int member1;

    MyStruct(int p0, int p1) : member0(p1), member1(p0){}
}
Run Code Online (Sandbox Code Playgroud)

在C++ 11之前,用户代码将停止编译,这会强制用户重写他的代码并使用构造函数.但是现在,代码将被编译并被解释为统一初始化:

MyStruct myVar = {0, 1}; // member0 = 1 and member1 = 0
Run Code Online (Sandbox Code Playgroud)

没有用户知道,更新他的库将使他的代码做一些非常不同的事情!


第二个例子

现在,让我们说我的库里有这样一个类:

class MyClass
{
public:
    MyClass(int size, int default = 0) : elements(size, default){}
private:
    std::vector<int> elements;
}
Run Code Online (Sandbox Code Playgroud)

用户可以像这样使用它:

MyClass myVar …
Run Code Online (Sandbox Code Playgroud)

uniform-initialization c++11 list-initialization

6
推荐指数
1
解决办法
350
查看次数

我不明白为什么我会收到有关有符号和无符号之间转换的警告,是我的编译器错误吗?

我有这个代码:

#include <cstdint>
#include <deque>
#include <iostream>

int main()
{
    std::deque<uint8_t> receivedBytes;
    int nbExpectedBytes = 1;

    if (receivedBytes.size() >= static_cast<size_t>(nbExpectedBytes))
    {
        std::cout << "here" << std::endl;
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

使用 -Wsign-conversion,这在我的 linux 笔记本电脑上编译时不会发出警告,但在要运行的嵌入式 linux 上,我收到以下警告:

temp.cpp:在函数“int main()”中:temp.cpp:10:33: 警告:从“int”转换为“std::deque::size_type {aka long unsigned int}”可能会改变结果 [-Wsign-conversion]

 if (receivedBytes.size() >= static_cast<size_t>(nbExpectedBytes))
                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

我就是不明白:

  • 我在我的 linux 笔记本电脑和嵌入式 linux 上都启用了 -Wsign-conversion,那么为什么我只在嵌入式 linux 上收到警告?
  • 我明确地从intto 转换size_t(它不应该产生警告,因为转换是显式的),然后将 asize_t与 a进行比较std::deque<unsigned char>::size_type,那么从有符号到无符号的隐式转换在哪里触发警告??!

我不禁认为嵌入式linux上的编译器在这里是错误的。我错过了什么吗?

编辑:在我的 linux 笔记本电脑上,我使用的是 g++ 9.3.0 版,而在嵌入式 linux 上,我使用的是 …

c++ embedded-linux

5
推荐指数
1
解决办法
94
查看次数

基于范围的for和其他增量

假设我们需要遍历一个容器。传统的for循环如下所示:

for (auto it = container.begin(), end = container.end();
     it != end; 
     ++it)
{
    doStuff(*it);
}
Run Code Online (Sandbox Code Playgroud)

而基于范围的for如下所示:

for (auto& element : container)
{
    doStuff(element);
}
Run Code Online (Sandbox Code Playgroud)

现在,在开发的某个时刻,我们意识到由于某种原因,我们需要在这些循环迭代中增加其他内容。

需要增加的可能是各种各样的东西。例如,如果我们将相关数据存储在相同大小的其他容器中,那么在进行迭代时,我们可能也需要将迭代器增加到这些容器中(尽管我希望标准库的未来版本能够使我们做更多的事情)通过结构化绑定和标准版本的boost :: range :: combine或其他方式来表达。

在下面,为简单起见,我们假设要为每个元素分配一个ID,因此需要增加的只是一个计数器。


现在,传统循环看起来像这样:

unsigned int elementID = 0u;
for (auto it = container.begin(), end = container.end();
     it != end;
     ++it, ++elementID)
{
    doStuff(*it, elementID);
}
Run Code Online (Sandbox Code Playgroud)

几乎任何东西都必须更改,并在++elementID后面加上,以++it确保无论每次迭代后计数器如何递增计数器。即使另一个程序员修改了循环的主体,并说在某些条件下提前进入下一个迭代continue,也不会冒着他们忘记增加计数器之类的风险。


现在,据我所知,使用基于范围的for进行增量的唯一方法是执行以下操作:

unsigned int elementID = 0u;
for (auto& element : container)
{
    doStuff(element, elementID);
    ++elementID;
}
Run Code Online (Sandbox Code Playgroud)

也就是说,将增量放入循环体内。

这方面的表现力较差 …

c++ for-loop c++11

4
推荐指数
1
解决办法
98
查看次数

为什么在比较 uint16_t 和 unsigned int 时出现符号问题?

我有这样的代码:

\n
#include <iostream>\nusing std::cout;\nusing std::endl;\n\nint main() {\n    uint16_t a = 0;\n    uint16_t b = 0;\n\n    if ( a - b < 3u )\n    {\n        cout << "cacahu\xc3\xa8te" << endl;\n    }\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

当我使用 g++ with 编译它时-Wall,我得到:

\n
temp.cpp: In function \xe2\x80\x98int main()\xe2\x80\x99:\ntemp.cpp:9:13: warning: comparison of integer expressions of different signedness: \xe2\x80\x98int\xe2\x80\x99 and \xe2\x80\x98unsigned int\xe2\x80\x99 [-Wsign-compare]\n    9 |  if ( a - b < 3u )\n      |       ~~~~~~^~~~\n
Run Code Online (Sandbox Code Playgroud)\n

如果我改为写入,则不会显示该警告if ( a - b < static_cast<uint16_t>(3u) …

c++ integer

4
推荐指数
1
解决办法
475
查看次数

如何为非类型模板类的特化定义声明之外的方法?

标题是满口的,但基本上我写了这样的东西:

enum EnumType{ValA, ValB};

template<EnumType> class A {};

template<>
class A<ValA>
{
private:
    double param;
public:
    A(double param);
};

template<>
A<ValA>::A(double param)
{
    // Do Stuff
}
Run Code Online (Sandbox Code Playgroud)

当我尝试编译它时,我得到:

错误:'A <(EnumType)0u> :: A(double)'的template-id'A <>'与任何模板声明都不匹配

我做错了吗?

在网上搜索类似的情况后,我试图删除template<>(即使我不明白为什么这会起作用),但后来我得到了

'A <(EnumType)0u> :: A(double)'的多重定义

我想,我可以代替template<>通过inline(我试着和它编译),但是,这并不觉得自己是正确的方式做到这一点(或者,如果是这样,我不明白为什么).

有人可以向我解释我写的内容有什么问题,为什么改变它似乎有效,以及正确的方法是什么?

c++ templates c++11

3
推荐指数
1
解决办法
58
查看次数

use-declarations是静态的吗?

我对使用声明有点困惑.我理解using foo::bar;将符号bar从命名空间foo导入当前命名空间,但这是静态还是动态发生的?

更具体地说,使用声明会导致开销吗?是否可以根据条件导入具有相同名称的不同符号?(这将是不好的做法,但我很好奇所有相同)

感觉它应该是静态的,但我找不到任何东西来证实这一点......

c++ using-directives

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