草庐IT

c++ - 有没有办法结合编译器防火墙(Pimpl)和默认可复制性的好处?

coder 2024-02-09 原文

假设我有一个带有私有(private)成员的类,这是类的客户不关心的实现细节。这个类是一个值类型,我们希望它是可复制的,例如

#include <boost/bimap.hpp>  // some header that pulls in many other files

class MyClass {
public:
    MyClass() {}
    ...
private:
    boost::bimap<Key,Value>   table;
};

现在,MyClass 的每个客户端都被迫引入许多它并不真正需要的 boost header ,从而增加了构建时间。但是,该类至少是可复制的。

如果我们引入编译器防火墙(Pimpl 习惯用法),那么我们可以将#include 依赖项移动到 cpp 文件,但由于 5 规则,现在我们必须做更多的工作:

// no extra #includes - nice
class MyClass {
public:
    MyClass() {}
    // ugh, I don't want this, just make it copyable!
    MyClass(const MyClass& rhs);
    MyClass(MyClass&& rhs);
    MyClass& operator=(const MyClass& rhs);
    MyClass& operator=(MyClass&& rhs);
    ~MyClass() {}
    ...
private:
    std::unique_ptr<MyClassImpl>  impl;
};

有没有一种技术既能获得编译器防火墙的好处,又能保留可复制性,这样我就不需要包含 5 条规则样板?

最佳答案

我认为这里最好的解决方案是构建您自己的深度复制智能指针。如果您将其调整为仅存储 Pimpls,应该不会太困难:

template <class P>
class pimpl_ptr
{
  std::unique_ptr<P> p_;

public:
  ~pimpl_ptr() = default;

  pimpl_ptr(const pimpl_ptr &src) : p_(new P(*src.p_)) {}
  pimpl_ptr(pimpl_ptr &&) = default;
  pimpl_ptr& operator= (const pimpl_ptr &src) { p_.reset(new P(*src.p_)); return *this; }
  pimpl_ptr& operator= (pimpl_ptr &&) = default;

  pimpl_ptr() = default;
  pimpl_ptr(P *p) : p_(p) {}

  P& operator* () const { return *p_; }
  P* operator-> () const { return &**this; }

  // other ctors and functions as deemed appropriate
};

只要记录它不支持指向基类子对象,就可以了。您可以通过不给它一个接受指针的构造函数来强制执行此操作,并通过 make_pimpl 强制执行构造:

template <class P>
class pimpl_ptr
{
  // as above, P* ctor is private
private:
  pimpl_ptr(P *p) : p_(p) {}

  template <class T, class... Arg>
  friend pimpl_ptr<T> make_pimpl(Arg&&... arg);
};

template <class T, class... Arg>
pimpl_ptr<T> make_pimpl(Arg&&... arg)
{
  return pimpl_ptr<T>(new T(std::forward<Arg>(arg)...));
}

关于c++ - 有没有办法结合编译器防火墙(Pimpl)和默认可复制性的好处?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26378266/

有关c++ - 有没有办法结合编译器防火墙(Pimpl)和默认可复制性的好处?的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby - 默认情况下使选项为 false - 2

    这是在Ruby中设置默认值的常用方法:classQuietByDefaultdefinitialize(opts={})@verbose=opts[:verbose]endend这是一个容易落入的陷阱:classVerboseNoMatterWhatdefinitialize(opts={})@verbose=opts[:verbose]||trueendend正确的做法是:classVerboseByDefaultdefinitialize(opts={})@verbose=opts.include?(:verbose)?opts[:verbose]:trueendend编写Verb

  3. ruby-on-rails - date_field_tag,如何设置默认日期? [ rails 上的 ruby ] - 2

    我想设置一个默认日期,例如实际日期,我该如何设置?还有如何在组合框中设置默认值顺便问一下,date_field_tag和date_field之间有什么区别? 最佳答案 试试这个:将默认日期作为第二个参数传递。youcorrectlysetthedefaultvalueofcomboboxasshowninyourquestion. 关于ruby-on-rails-date_field_tag,如何设置默认日期?[rails上的ruby],我们在StackOverflow上找到一个类似的问

  4. ruby-on-rails - 在默认方法参数中使用 .reverse_merge 或 .merge - 2

    两者都可以defsetup(options={})options.reverse_merge:size=>25,:velocity=>10end和defsetup(options={}){:size=>25,:velocity=>10}.merge(options)end在方法的参数中分配默认值。问题是:哪个更好?您更愿意使用哪一个?在性能、代码可读性或其他方面有什么不同吗?编辑:我无意中添加了bang(!)...并不是要询问nobang方法与bang方法之间的区别 最佳答案 我倾向于使用reverse_merge方法:option

  5. ruby-on-rails - 有没有办法为 CarrierWave/Fog 设置上传进度指示器? - 2

    我在Rails应用程序中使用CarrierWave/Fog将视频上传到AmazonS3。有没有办法判断上传的进度,让我可以显示上传进度如何? 最佳答案 CarrierWave和Fog本身没有这种功能;你需要一个前端uploader来显示进度。当我不得不解决这个问题时,我使用了jQueryfileupload因为我的堆栈中已经有jQuery。甚至还有apostonCarrierWaveintegration因此您只需按照那里的说明操作即可获得适用于您的应用的进度条。 关于ruby-on-r

  6. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  7. ruby-on-rails - 如何在 Rails 中设置路由的默认格式? - 2

    路由有如下代码:resources:orders,only:[:create],defaults:{format:'json'}resources:users,only:[:create,:update],defaults:{format:'json'}resources:delivery_types,only:[:index],defaults:{format:'json'}resources:time_corrections,only:[:index],defaults:{format:'json'}是否可以使用1个字符串为所有资源设置默认格式,每行不带“默认值”散列?谢谢。

  8. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  9. Ruby 默认将 IRB 配置为 Pretty_Inspect - 2

    我是ruby​​的新手,正在配置IRB。我喜欢pretty-print(需要'pp'),但总是输入pp来漂亮地打印它似乎很麻烦。我想做的是默认情况下让它漂亮地打印出来,所以如果我有一个var,比如说,'myvar',然后键入myvar,它会自动调用pretty_inspect而不是常规检查。我从哪里开始?理想情况下,我将能够向我的.irbrc文件添加一个自动调用的方法。有什么想法吗?谢谢! 最佳答案 irb中默认pretty-print对象正是hirb被迫去做。Theseposts解释hirb如何将几乎所有内容转换为ascii表。虽

  10. ruby - 有没有办法从 ruby​​ case 语句中访问表达式? - 2

    我想从then子句中访问c​​ase语句表达式,即food="cheese"casefoodwhen"dip"then"carrotsticks"when"cheese"then"#{expr}crackers"else"mayo"end在这种情况下,expr是食物的当前值(value)。在这种情况下,我知道,我可以简单地访问变量food,但是在某些情况下,该值可能无法再访问(array.shift等)。除了将expr移出到局部变量然后访问它之外,是否有直接访问caseexpr值的方法?罗亚附注我知道这个具体示例很简单,只是一个示例场景。 最佳答案

随机推荐