我想比较两个 std::weak_ptr 或一个 std::weak_ptr 和一个 std::shared_ptr 是否相等。
我想知道的是每个weak_ptr/shared_ptr指向的对象是否相同。 不仅如果地址不匹配,而且如果底层对象被删除然后偶然用相同的地址重建,则比较应该会产生负面结果。
所以基本上,即使分配器保留相同的地址,我也希望这个断言成立:
auto s1 = std::make_shared<int>(43);
std::weak_ptr<int> w1(s1);
s1.reset();
auto s2 = std::make_shared<int>(41);
std::weak_ptr<int> w2(s2);
assert(!equals(w1,w2));
weak_ptr 模板不提供相等运算符,据我了解,它是 for a good reason .
所以一个简单的实现应该是这样的:
template <typename T, typename U>
inline bool naive_equals(const std::weak_ptr<T>& t, const std::weak_ptr<U>& u)
{
return !t.expired() && t.lock() == u.lock();
}
template <typename T, typename U>
inline bool naive_equals(const std::weak_ptr<T>& t, const std::shared_ptr<U>& u)
{
return !t.expired() && t.lock() == u;
}
如果第一个weak_ptr同时过期,它产生0。如果没有,我将weak_ptr升级为shared_ptr并比较地址。
问题是我必须锁定weak_ptr 两次(一次)!恐怕这需要太多时间。
我想出了这个:
template <typename T, typename U>
inline bool equals(const std::weak_ptr<T>& t, const std::weak_ptr<U>& u)
{
return !t.owner_before(u) && !u.owner_before(t);
}
template <typename T, typename U>
inline bool equals(const std::weak_ptr<T>& t, const std::shared_ptr<U>& u)
{
return !t.owner_before(u) && !u.owner_before(t);
}
检查 u 的所有者 block 是否不在 t 之前,并且 t 不在 u 之前,所以 t == u。
这是否如我所愿?从不同的 shared_ptr 创建的两个weak_ptr 是否总是以这种方式比较不相等? 还是我错过了什么?
编辑:我为什么要首先这样做? 我想要一个带有共享指针的容器,并且我想分发对其中对象的引用。 我不能使用迭代器,因为它们可能会失效。我可以分发(整数)ID,但这会导致唯一性问题,并且需要 map 类型和复杂的搜索/插入/删除操作。 这个想法是使用 std::set 并将指针本身(封装在包装器类中)作为键,以便客户端可以使用weak_ptr 访问集合中的对象。
最佳答案
完全重写这个答案,因为我完全误解了。这是一件很难做到的事情!
std::weak_ptr和std::shared_ptr的通常实现符合标准的是有两个堆对象:托管对象和< em="">控制 block 。每个指向同一个对象的共享指针都包含一个指向该对象和控制 block 的指针,每个弱指针也是如此。控制 block 记录共享指针的个数和弱指针的个数,当共享指针的个数达到0时释放被管理对象;当弱指针的数量也达到0时,控制 block 本身被释放。
由于共享或弱指针中的对象指针可以指向实际托管对象的子对象,例如一个基类、一个成员,甚至是托管对象拥有的另一个堆对象。
S0 ----------______ MO <------+
\__ `----> BC |
\_ _______--------> m1 |
___X__ m2 --> H |
S1 -/ \__ __----------------^ |
\___ _____X__ |
____X________\__ |
W0 /----------------`---> CB -------+
s = 2
w = 1
这里我们有两个共享指针,分别指向托管对象的基类和成员,以及指向托管对象拥有的堆对象的弱指针;控制 block 记录了存在两个共享指针和一个弱指针。控制 block 还有一个指向托管对象的指针,当托管对象过期时,它使用它来删除托管对象。
owner_before/owner_less 语义是通过控制 block 的地址来比较共享指针和弱指针,保证不改变,除非指针本身被修改;即使弱指针过期,因为所有共享指针都已被破坏,它的控制 block 仍然存在,直到所有弱指针也被破坏。
所以您的 equals 代码绝对正确且线程安全。
问题在于它与 shared_ptr::operator== 不一致,因为它比较对象指针,并且具有相同控制 block 的两个共享指针可以指向不同的对象(如上)。
为了与 shared_ptr::operator== 保持一致,编写 t.lock() == u 绝对没问题;但是请注意,如果它返回 true 则仍然不能确定弱指针是另一个共享指针的弱指针;它可能是一个别名指针,因此在下面的代码中仍然可能过期。
但是,比较控制 block 的开销较小(因为它不需要查看控制 block ),并且如果您不使用别名指针,将给出与 == 相同的结果。
我认为这里的标准存在缺陷;添加一个 owner_equals 和 owner_hash 将允许在无序容器中使用 weak_ptr 并且给定 owner_equals 它实际上变得比较明智相等的弱指针,因为您可以安全地比较控制 block 指针然后对象指针,因为如果两个弱指针具有相同的控制 block ,那么您知道两者都或都没有过期。可能是下一个版本的标准。
关于c++ - 等式比较 std::weak_ptr,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12301916/
我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
如何将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%}定义的变量,我
方法应返回-1,0或1分别表示“小于”、“等于”和“大于”。对于某些类型的可排序对象,通常将排序顺序基于多个属性。以下是可行的,但我认为它看起来很笨拙:classLeagueStatsattr_accessor:points,:goal_diffdefinitializepts,gd@points=pts@goal_diff=gdenddefothercompare_pts=pointsother.pointsreturncompare_ptsunlesscompare_pts==0goal_diffother.goal_diffendend尝试一下:[LeagueStats.new(
我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么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=
我有两个文本文件,master.txt和926.txt。如果926.txt中有一行不在master.txt中,我想写入一个新文件notinbook.txt。我写了我能想到的最好的东西,但考虑到我是一个糟糕的/新手程序员,它失败了。这是我的东西g=File.new("notinbook.txt","w")File.open("926.txt","r")do|f|while(line=f.gets)x=line.chompifFile.open("master.txt","w")do|h|endwhile(line=h.gets)ifline.chomp!=xputslineendende
出于某种原因,heroku尝试要求dm-sqlite-adapter,即使它应该在这里使用Postgres。请注意,这发生在我打开任何URL时-而不是在gitpush本身期间。我构建了一个默认的Facebook应用程序。gem文件:source:gemcuttergem"foreman"gem"sinatra"gem"mogli"gem"json"gem"httparty"gem"thin"gem"data_mapper"gem"heroku"group:productiondogem"pg"gem"dm-postgres-adapter"endgroup:development,:t
我正在尝试对某些帖子的评论使用简单的身份验证。用户使用即时ID和密码输入评论我使用“bcrypt”gem将密码存储在数据库中。在comments_controller.rb中像这样@comment=Comment.new(comment_params)bcrypted_pwd=BCrypt::Password.create(@comment.user_pwd)@comment.user_pwd=bcrypted_pwd当用户想要删除他们的评论时,我使用data-confirm-modalgem来确认数据在这部分,我必须解密用户输入的密码以与数据库中的加密密码进行比较我怎样才能解密密码,