小编Pap*_*ter的帖子

键入安全枚举位标志

我想为我当前的问题使用一组位标志.这些标志(很好地)被定义为一部分enum,但是据我所知,当你OR从枚举中获得两个值时,OR操作的返回类型具有类型int.

我目前正在寻找的是一种解决方案,它允许位掩码的用户保持类型安全,因此我创建了以下重载 operator |

enum ENUM
{
    ONE     = 0x01,
    TWO     = 0x02,
    THREE   = 0x04,
    FOUR    = 0x08,
    FIVE    = 0x10,
    SIX     = 0x20
};

ENUM operator | ( ENUM lhs, ENUM rhs )
{
    // Cast to int first otherwise we'll just end up recursing
    return static_cast< ENUM >( static_cast< int >( lhs ) | static_cast< int >( rhs ) );
}

void enumTest( ENUM v )
{
}

int …
Run Code Online (Sandbox Code Playgroud)

c++ enums bitwise-operators c++03

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

std :: map\templates /插入移动值

目前我正在阅读C++的1篇论文,目前我正在尝试理解n3873题为" 改进的插入接口的独特键映射"的论文.该文件指出insert和emplace方法存在问题,它说明了以下示例的问题:

std::map<std::string, std::unique_ptr<Foo>> m;
m["foo"];

std::unique_ptr<Foo> p(new Foo);
auto res = m.emplace("foo", std::move(p));
Run Code Online (Sandbox Code Playgroud)

在上面的代码之后,它表达了以下内容:

有什么价值p?目前p尚未说明是否已移出.(答案是它取决于库的实现.)

好吧,我在寻找前一个引用的解释时遇到了麻烦,主要是因为我无法找到标准中指定的位置,如上所述移动或不移动的代码p是实现定义的; 期待n3690标准关联容器部分(23.2.4)关于emplace(args)(插入一个用它构造的value_type对象)和方法只提到插入或放置了值...tstd::forward<Args>(args)insert(t)

...当且仅当容器中没有元素且密钥等于密钥的时候t.

关于移动(或不移动)t价值的一句话; 另一方面,p托管内存无论如何都被释放(如果p在没有插入后移动被释放,并且如果没有被移动则在范围的末尾被释放)不是吗?


介绍之后,让我问下列问题:

  • 为什么在将值插入/放入已经具有插入键的关联容器中时移动值,将值设置为未指定状态?
  • 措辞在哪里,这个操作是实现定义的?
  • p这个例子会发生什么?它真的被释放了吗?

如果问题看起来很愚蠢或有明显的答案,请尝试原谅,这可能是因为我缺乏英语理解能力,或者因为我不习惯潜入标准论文.任何指导将不胜感激.

c++ map c++14

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

命名参数是否可用于模板模板参数

如果我需要foo使用template-template参数定义模板函数,我通常会执行以下操作:

// Notice that the template parameter of class T is unnamed.
template <template <typename> class T> void f() { std::cout << "Yay!\n"; }
Run Code Online (Sandbox Code Playgroud)

请注意,template-template参数的template参数是未命名的,但我们可以为此参数指定一个名称:

// Now the template parameter of class T is named INNER.
template <template <typename INNER> class T> void f(const INNER &inner)
{ std::cout << inner << " Yay!\n"; }
Run Code Online (Sandbox Code Playgroud)

这似乎没有用,因为我无法INNER在函数中提供参数,上面的代码会产生以下错误:

错误:'INNER'未命名类型

令我惊讶typename INNERtypename是,在为了命名类型之后,所有关键字都没有命名类型.无论如何,这很容易修复:

// Now INNER is the name of the template parameter of class T and …
Run Code Online (Sandbox Code Playgroud)

c++ templates template-templates

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

用于序列化/反序列化的标准C++代码

我已经使用硬件API很长一段时间了,几乎所有我工作过的API都有一个C接口.因此,在很多时候我使用裸news,不安全的缓冲和许多用C++代码包装的C函数.最后,C纯代码和C++纯代码之间的边界在我的脑海中搞砸了(我不知道澄清这个前沿是否有用).

现在,由于一些新的编码风格要求,我需要将所有怀疑不安全的代码重构为用C++编写的更安全的代码(假设C++代码更安全),最终目标是使用C++带来的工具.

所以,为了摆脱我的困惑,我正在寻求关于C/C++的几个主题的帮助.

memcpy VS std::copy

AFAIK memcpy是一个位于C库中的函数,因此它不是C++ ish; 另一方面std::copy是STL中的一个函数,所以它是纯C++.

  • 但是,这是真的吗?毕竟,如果数据是平凡可复制的,std::copy则会调用std::memcpy(进入cstring标题).
  • 将所有memcpy调用重构为std::copy调用将使代码更"纯C++"?

为了处理新的代码样式要求,我决定继续使用memcpy重构,有一些关于memcpy和的问题std::copy:

memcpy类型不安全,因为它适用于原始void指针,可以管理任何类型的指针,无论它的类型如何,但同时非常灵活,std::copy缺乏这种灵活性,确保类型安全.乍一看,memcpy是使用序列化和反序列化例程的最佳选择(这是我确实使用的真实情况),例如,通过自定义串行端口库发送一些值:

void send(const std::string &value)
{
    const std::string::size_type Size(value.size());
    const std::string::size_type TotalSize(sizeof(Size) + value.size());
    unsigned char *Buffer = new unsigned char[TotalSize];
    unsigned char *Current = Buffer;

    memcpy(Current, &Size, sizeof(Size));
    Current += sizeof(Size);

    memcpy(Current, value.c_str(), Size);

    sendBuffer(Buffer, TotalSize);

    delete []Buffer;
}
Run Code Online (Sandbox Code Playgroud)

上面的代码运行正常,但看起来很糟糕; …

c++ serialization buffer allocator

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

将静态变量声明为函数/成员函数是不好的做法?

最近一位同事向我展示了这样的代码:

void SomeClass::function()
{
    static bool init = false;

    if (!init)
    {
        // hundreds of lines of ugly code
    }

    init = true;
}
Run Code Online (Sandbox Code Playgroud)

他想检查是否SomeClass已初始化,以便每个Someclass实例执行一次代码,但事实是SomeClass在程序的所有生命周期中只存在一个实例.

他的问题是关于init静态变量,关于何时初始化.我已回答初始化发生一次,因此该值将false在第一次调用true时及其生命周期的剩余时间.在回答之后,我已经补充说这样使用静态变量是不好的做法,但我无法解释原因.

到目前为止我一直在考虑的原因如下:

  • 可以使用非静态成员变量来实现static bool initinto 的行为SomeClass::function.
  • 其他函数SomeClass无法检查static bool init值,因为它的可见性仅限于void SomeClass::function()范围.
  • 静态变量不是OOPish,因为它们定义了一个全局状态而不是一个对象状态.

这个原因看起来很糟糕,不完整,对我来说不是很具体,所以我要求更多理由来解释为什么在函数和成员函数空间中使用静态变量是一种不好的做法.

谢谢!

c++ static

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

如何读取二进制数作为输入?

有没有办法让用户在C或C++中输入二进制数?

如果我们写类似的东西

int a = 0b1010;
std::cout << a << std::endl
Run Code Online (Sandbox Code Playgroud)

然后输出结果为10(使用适当的编译器扩展时).

但是当我们试着写的时候

int n;
std::cin >> n;
int t = 0bn;
Run Code Online (Sandbox Code Playgroud)

它给了我们一个错误所以任何人都可以建议我们如何直接读取二进制数作为输入而不是使用字符串来存储输入?

c c++ user-input input c++14

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

使用函数指针的Specialize模板,取决于模板参数

我想有一个嵌套值的模板,应该由给定的初始化函数初始化:

template <typename T, T(INIT)()> struct Foo
{
    T value = INIT();
};
Run Code Online (Sandbox Code Playgroud)

它可以这样使用:

// Some random type only instanceable through factory()
struct Bar
{
    int bar{};
private:
    // The only way to create a Bar is through factory()
    friend Bar factory();
    Bar() {};
};

Bar factory() { return {}; }

Foo<Bar, factory> foo;
Run Code Online (Sandbox Code Playgroud)

但是,如果没有提供函数,模板应该尝试默认初始化嵌套值,所以我试图专门化模板:

template <typename T> struct Foo<T, nullptr>
{
    T value{};
};
Run Code Online (Sandbox Code Playgroud)

我的想法是这样使用它:

struct Baz{};

Foo<Bar, factory> foo; // Nested Bar have Bar::bar initialized through factory function. …
Run Code Online (Sandbox Code Playgroud)

c++ templates function-pointers

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

非void函数中的空返回,是未定义的行为?

在阅读了关于控制主题的答案到达非void函数的结尾之后,我没有看到任何答案,特别是使用空return语句退出非void函数的情况:

int return_integer() { return; }  // empty return in non-void function
Run Code Online (Sandbox Code Playgroud)

到目前为止我在C标准中发现的是:

6.8.6.4退货声明

约束

  1. return带有表达式的语句不应出现在返回类型为的函数中void.return没有表达式的语句只能出现在返回类型为的函数中void.

标准引用说明我们应该对我们的return语句void和非void函数做什么,当忽略约束时会发生什么,在文档的其他部分中提到:

6.9.1函数定义

  1. 如果}终止了函数,并且调用者使用了函数调用的值,则行为是未定义的.

以前的标准引用声明,如果我们使用函数的返回值,并且在到达结束花括号(})之后结束,则会发生UB ,因此我们在下面的代码中有UB:

int UB(int x) { if (x) return x; }

printf("%d", UB(1)); // Correct
printf("%d", UB(0)); // Undefined behavior
Run Code Online (Sandbox Code Playgroud)

UB(1)调用中函数1通过下面的return x;指令返回if (x); 在UB(0)调用中 …

c standards

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

C和C++中的可变长度数组(VLA)

可能重复:
文件范围内可变修改的数组

我有一些关于VLA及其行为的概念,我需要澄清一下.

自C99起AFIK可以将VLA声明为本地范围:

int main(int argc, char **argv)
{
    // function 'main' scope
    int size = 100;
    int array[size];
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

但它在全球范围内被禁止:

const int global_size = 100;
int global_array[global_size]; // forbidden in C99, allowed in C++

int main(int argc, char **argv)
{
    int local_size = 100;
    int local_array[local_size];
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

上面的代码在C99中声明了一个VLA,因为const修饰符不会创建编译时值.在C++中global_size是一个编译时值,因此,global_array不会成为VLA.

我需要知道的是:我的推理是否正确?我描述的行为是正确的吗?

我也想知道:为什么不允许全球范围内的VLA?在C和C++中是否被禁止?数组在全局和局部范围内的行为有什么不同?

c c++ arrays variable-length-array

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

用户定义的默认构造函数效率较低吗?

几天前,在阅读标准C++新闻时,我读过有关C++ 11中默认函数的帖子,在那篇文章中提到用户定义的构造函数效率低于编译器生成的函数:

用户定义的默认构造函数的效率低于编译器隐式定义的默认构造函数.

继续阅读,有一个例子,用户定义的构造函数被标记为默认值,然后说:

显式默认构造函数比手动编程的默认构造函数更有效.

我不明白这些断言,所以我想知道:

  • 为什么用户默认构造函数(或特殊成员函数)的效率低于编译器隐式定义的那个?
  • 如何通过明确默认构造函数(或特殊成员函数)来提高效率?
  • 选择默认构造函数(或特殊成员函数)以及效率如何影响此决策时必须遵循哪些指导原则?

c++ constructor defaulted-functions

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