【问题标题】:Convenient way to call GC::KeepAlive in C++/CLI scenarios?在 C++/CLI 场景中调用 GC::KeepAlive 的便捷方式?
【发布时间】:2009-05-07 14:07:11
【问题描述】:

我正在使用 C++/CLI 编写一些托管包装器。问题是 GC 有时会在我使用它的非托管成员时处理该对象。 (我认为这种行为很疯狂,但这是另一个话题)。更多详情见:

Finalizer launched while its object was still being used http://blogs.msdn.com/cbrumme/archive/2003/04/19/51365.aspx

我正在寻找一种方便的呼叫方式:

GC::KeepAlive(this);

在每个方法的末尾。对于普通的旧 void 方法,这很容易,但对于返回值的方法,它有点棘手。

int ComputeInt() {
   return m_unmanagedMember->LongRunningComputation();
}

必须变成:

int ComputeInt() {
   int tmp = m_unmanagedMember->LongRunningComputation();
   GC::KeepAlive(this);
   return tmp;
}

这对我来说有点难看。

我考虑了一个在 dtor 中调用 GC::KeepAlive 的保护类,但这会在每个方法中引发 ctor 和 dtor 调用,这似乎有点过分。

是否有任何可用的 C++ 魔法可以让我避免临时变量?

编辑

我意识到 try + finally 会为我解决问题,即:

int ComputeInt() {
   try {
      return m_unmanagedMember->LongRunningComputation();
   } finally {
      GC::KeepAlive(this);
   }
}

最后,我实现了一个宏来处理这个问题:

#define KEEPALIVE_RETURN(x) try {\
    return x;\
} finally { System::GC::KeepAlive(this); }

【问题讨论】:

  • 我不认为你可以做守卫,因为你必须在非托管类中持有一个托管引用才能做到这一点——如果可以的话,你可以让 ctor 和 dtor 内联,所以这基本上只是一个 KeepAlive 调用(但是,就像我说的,我认为这是不可能的)
  • 我遇到了同样的事情:谢谢!我一直在绕圈子,试图找到导致堆损坏的位置,这一切都是由于终结器在对象仍在使用时释放内存...... DOH......

标签: .net c++ garbage-collection finalizer


【解决方案1】:

怎么样(不是真正检查语法)

template<class RType>
const RType& KeepAliveRet(Object^ o, const RType& ret)
{
    GC::KeepAlive(o);
    return ret;
} 


int ComputeInt() {
   return KeepAliveRet(this, m_unmanagedMember->LongRunningComputation());
}

【讨论】:

    猜你喜欢
    • 2011-11-24
    • 2014-03-24
    • 2010-10-10
    • 2019-03-03
    • 2015-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-27
    相关资源
    最近更新 更多