我需要使用一个非常大且复杂的仅 header 类(想想 boost::multiprecision::cpp_bin_float<76>,下面称为 BHP),我想将其隐藏在类似 pimpl 的实现后面,纯粹是为了在较大的项目中减少编译时间(将 Boost 类替换为 std::complex<double> 减少了大约 50% 的编译时间)。
但是,我想避免动态内存分配。因此,这样的事情看起来很自然(暂时忽略可以使用 aligned_storage 或 alignas 避免的对齐问题):
struct Hidden {
char data[sz];
Hidden& punned(Hidden const& other);
};
Hidden::punned然后可以在单个翻译单元中定义以转换 data至 BHP* ,对其采取行动,不要用 170k LOC 的头文件污染所有其他翻译单元。一个可能的实现可能是
Hidden& Hidden::punned(Hidden const& other) {
*(BHP*)(data) += *(BHP*)(other.data);
return *this;
}
当然,这是未定义的行为,因为我们访问了一个 BHP 类型的对象通过 char 类型的指针,因此违反了严格的别名规则。正确的做法是:
Hidden& Hidden::proper(Hidden const& other) {
BHP tmp; std::memcpy(&tmp, data, sz);
BHP tmp2; std::memcpy(&tmp2, other.data, sz);
tmp += tmp2;
std::memcpy(data, &tmp, sz);
return *this;
}
现在这些 memcpy 可能看起来“很明显”电话可以优化掉。不幸的是,情况并非如此,它们仍然存在并制作proper()比 punned() 大得多.
我想知道 a) 将数据直接存储在 Hidden 中的正确方法是什么对象和 b) 避免不必要的拷贝来重新解释它,并且 c) 避免违反严格的对齐规则,并且 d) 不要携带指向存储区域的额外指针。
有一个godbolt link here ;请注意,我测试的所有编译器(GCC 4.9 - trunk、Clang 3.9、4.0 和 5.0 以及 Intel 18)都没有“优化”memcpy。某些版本的 GCC(例如 5.3)也直接提示违反了严格的别名规则,尽管并非所有版本都这样做。我还插入了一个 Direct知道 BHP 的类因此可以直接调用它,但我想避免这种情况。
最小工作示例:
#include <cstring>
constexpr std::size_t sz = 64;
struct Base {
char foo[sz];
Base& operator+=(Base const& other) { foo[0] += other.foo[0]; return *this; }
};
typedef Base BHP;
// or:
//#include <boost/multiprecision/cpp_bin_float.hpp>
//typedef boost::multiprecision::number<boost::multiprecision::cpp_bin_float<76> > BHP;
struct Hidden {
char data[sz];
Hidden& proper(Hidden const& other);
Hidden& punned(Hidden const& other);
};
Hidden& Hidden::proper(Hidden const& other) {
BHP tmp; std::memcpy(&tmp, data, sz);
BHP tmp2; std::memcpy(&tmp2, other.data, sz);
tmp += tmp2;
std::memcpy(data, &tmp, sz);
return *this;
}
Hidden& Hidden::punned(Hidden const& other) {
*(BHP*)(data) += *(BHP*)(other.data);
return *this;
}
struct Direct {
BHP member;
Direct& direct(Direct const& other);
};
Direct& Direct::direct(Direct const& other) {
member += other.member;
return *this;
}
struct Pointer {
char storage[sz];
BHP* data;
Pointer& also_ok(Pointer const& other);
};
Pointer& Pointer::also_ok(Pointer const& other) {
*data += *other.data;
return *this;
}
76>最佳答案
This, of course, is undefined behaviour, because we access an object of type
BHPthrough a pointer of type char.
其实不是这样的。通过 char* 访问 is fine 假设那里确实有一个BHP对象。也就是说,只要双方都有:
new (data) BHP(...);
那么这完全没问题:
*(BHP*)(data) += *(BHP*)(other.data);
只需确保您的字符数组也是 alignas(BHP)。
请注意,gcc 有时不喜欢您重新解释 char[],因此您可以选择使用类似 std::aligned_storage_t 的内容.
关于c++ - memcpy 在尝试 ‘fast’ pimpl 期间未优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47815831/
我正在用Ruby编写一个简单的程序来检查域列表是否被占用。基本上它循环遍历列表,并使用以下函数进行检查。require'rubygems'require'whois'defcheck_domain(domain)c=Whois::Client.newc.query("google.com").available?end程序不断出错(即使我在google.com中进行硬编码),并打印以下消息。鉴于该程序非常简单,我已经没有什么想法了-有什么建议吗?/Library/Ruby/Gems/1.8/gems/whois-2.0.2/lib/whois/server/adapters/base.
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
由于fast-stemmer的问题,我很难安装我想要的任何rubygem。我把我得到的错误放在下面。Buildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingfast-stemmer:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcreatingMakefilemake"DESTDIR="cleanmake"DESTDIR=
我是Google云的新手,我正在尝试对其进行首次部署。我的第一个部署是RubyonRails项目。我基本上是在关注thisguideinthegoogleclouddocumentation.唯一的区别是我使用的是我自己的项目,而不是他们提供的“helloworld”项目。这是我的app.yaml文件runtime:customvm:trueentrypoint:bundleexecrackup-p8080-Eproductionconfig.ruresources:cpu:0.5memory_gb:1.3disk_size_gb:10当我转到我的项目目录并运行gcloudprevie
如何将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.你能做的最好的事情是:
我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我
我正在关注Hartl的railstutorial.org并已到达11.4.4:Imageuploadinproduction.我做了什么:注册亚马逊网络服务在AmazonIdentityandAccessManagement中,我创建了一个用户。用户创建成功。在AmazonS3中,我创建了一个新存储桶。设置新存储桶的权限:权限:本教程指示“授予上一步创建的用户读写权限”。但是,在存储桶的“权限”下,未提及新用户名。我只能在每个人、经过身份验证的用户、日志传送、我和亚马逊似乎根据我的名字+数字创建的用户名之间进行选择。我已经通过选择经过身份验证的用户并选中了上传/删除和查看权限的框(而不
我正在尝试循环哈希数组。当我到达获取枚举器开始循环的位置时,出现以下错误:undefinedmethod`[]'fornil:NilClass我的代码如下所示:defextraireAttributs(attributsParam)classeTrouvee=falsescanTrouve=falseownerOSTrouve=falseownerAppTrouve=falseresultat=Hash.new(0)attributs=Array(attributsParam)attributs.eachdo|attribut|#CRASHESHERE!!!typeAttribut=a
我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“
有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=