c – 具有标准布局结构的RVO,没有任何构造函数

我有一个代表二进制消息的结构.我想编写一个函数来从缓冲区获取一个这样的记录(无论是文件还是套接字,都不重要):
template <typename Record>
Record getNext();

现在我可以这样写:

template <typename Record>
Record getNext() {
    Record r;
    populateNext(reinterpret_cast<char*>(&r),// maybe ::read()
                 sizeof(r));                   // or equivalent
    return r;
}

这很好,给了我RVO的好处.但是,它将调用Record的认构造函数,它可能由具有非希望认构造函数的类型组成,这些构造函数可以避免使用 – 这些不一定是POD类型,但它们是标准布局.

有没有办法写入getNext(),以避免在Record上避免任何构造函数(认或复制/移动)?理想情况下,当用户拨打:

auto record = getNext<Record>();

缓冲区直接读入记录的内存.这可能吗?

解决方法

no_init是一个no_init_t类型的常量.

如果从no_init_t构建一个pod,您将获得一个未初始化的pod,并且(假设elision)没有任何事情要做.

如果从no_init_t构造非pod,则必须覆盖构造函数,并使其不初始化数据.通常class_name(no_init_t):field1(no_init),field2(no_init){}将会这样做,有时class_name(no_init_t){}将会执行(假设所有内容都是pod).

然而,从每个成员的no_init构造可以作为一个健全检查,成员确实是pod.从no_init构造的非pod类将无法编译,直到您编写no_init_t构造函数.

这样(每个成员构造函数都不需要)确实会产生一些令人讨厌的DRY失败,但是我们没有反思,所以你会重复一遍,喜欢它.

namespace {
  struct no_init_t {
    template<class T,class=std::enable_if_t<std::is_pod<T>{}>>
    operator T()const{
      T tmp;
      return tmp;
    }
    static no_init_t instance() { return {}; }
    no_init_t(no_init_t const&) = default;
  private:
    no_init_t() = default;
  };
  static const no_init = no_init_t::instance();
}


struct Foo {
  char buff[1000];
  size_t hash;
  Foo():Foo(""){}
  template<size_t N,class=std::enable_if_t< (N<=sizeof(buff)) >>
  Foo( char const(&in)[N] ) {
    // some "expensive" copy and hash
  }
  Foo(no_init_t) {} // no initialization!
};
struct Record {
  int x;
  Foo foo;
  Record()=default;
  Record(no_init_t):
    x(no_init),foo(no_init)
  {}
};

现在我们可以用no_init构造Record,并且不会被初始化.

每个POD类都没有初始化.每个非POD类都必须提供一个no_init_t构造函数(可能最好实现非初始化).

然后你可以随便memcpy.

这需要修改您的类型及其包含的类型,以支持非初始化.

相关文章

本程序的编译和运行环境如下(如果有运行方面的问题欢迎在评...
水了一学期的院选修,万万没想到期末考试还有比较硬核的编程...
补充一下,先前文章末尾给出的下载链接的完整代码含有部分C&...
思路如标题所说采用模N取余法,难点是这个除法过程如何实现。...
本篇博客有更新!!!更新后效果图如下: 文章末尾的完整代码...
刚开始学习模块化程序设计时,估计大家都被形参和实参搞迷糊...