【问题标题】:Crash in shared_ptr destructor in templated function模板化函数中的 shared_ptr 析构函数崩溃
【发布时间】:2020-04-03 20:40:01
【问题描述】:

在我的 32 位 VS2015 应用程序中,我有一个模板函数,可以访问库 (BTK) 的函数。根据此函数的类型,调用此库的函数的特定重载。

这很好用,但最近我在另一个(也是 VS2015 32 位)应用程序中使用相同的代码和库(相同的二进制文件和代码),并且它在 shared_ptr 的析构函数中出现段错误/访问冲突。准确地说,它在使用计数的(联锁)递减时崩溃。

void _Decref()
{   // decrement use count
    if (_MT_DECR(_Uses) == 0) // BOOM
    {   // destroy managed resource, decrement weak reference count
        _Destroy();
        _Decwref();
    }
}

现在有趣的部分来了,当我用非模板版本替换我的模板函数时,它可以正常工作..

所以,如果我替换这个:

template<class T>
bool SetParameters(const std::string& group, const std::string& param, const std::vector<T>& values, const std::vector<uint8_t>& dims)
{
    btk::MetaData::Pointer pParam = GetBtkMetaData(group, param);
    if (!pParam)
    {
        pParam = AddBtkMetaData(group, param);
    }

    if (!pParam->HasInfo())
    {
        pParam->SetInfo(btk::MetaDataInfo::New(dims, values));
    }
    else pParam->GetInfo()->SetValues(dims, values);

    return true;
}

用这个:

bool C3DFile::SetParameters(const std::string& group, const std::string& param, const std::vector<int16_t>& values, const std::vector<uint8_t>& dims)
{
    btk::MetaData::Pointer pParam = GetBtkMetaData(group, param);
    if (!pParam)
    {
        pParam = AddBtkMetaData(group, param);
    }

    if (!pParam->HasInfo())
    {
        pParam->SetInfo(btk::MetaDataInfo::New(dims, values));
    }
    else pParam->GetInfo()->SetValues(dims, values);

    return true;
}

它工作得很好......显然,模板实例化对共享指针有一些影响。我有三个问题:

  • 模板可以对此产生什么样的影响?我可以想象代码实例化可能会产生一些影响,但我不确定。

  • 为什么模板化版本可以在一个 32 位 VS2015 应用程序中使用相同的二进制文件等,而在另一个应用程序中却不行? (我需要求助于非模板函数)

  • 哪些编译器/链接器选项可能相关?我检查了编译器和链接器选项,但找不到相关的区别。

任何帮助将不胜感激。

本

【问题讨论】:

  • btk::MetaDataInfo::New 是否有一些重载?
  • 是的,很多,适用于 int、double,但也适用于具有这些类型的向量。奇怪的是,它在一个应用程序中有效,但在另一个应用程序中无效。

标签: c++ templates visual-studio-2015 x86 shared-ptr


【解决方案1】:

模板可以对此产生什么样的影响?我可以想象代码实例化可能会产生一些影响,但我不确定。

ADL:模板方法将使用 ADL 查找依赖方法(在您的情况下为 btk::MetaDataInfo::New(dims, values)),而非模板仅考虑可见声明,因此可能存在差异。

例子:

struct A{};

void fooT(const void*) { std::cout << "void*\n"; }
template <typename T> void barT(const T* p) { fooT(p); }
void fooT(const A*) { std::cout << "A*\n"; }

void foo(const void*) { std::cout << "void*\n"; }
void bar(const A* p) { foo(p); }
void foo(const A*) { std::cout << "A*\n"; }

int main()
{
    A a{};

    barT(&a); // fooT(const A*)   -> A*
    bar(&a);  // foo(const void*) -> void*
}

Demo

【讨论】:

  • 啊,有道理,但是每个应用程序怎么会有不同呢?
  • 可能#include 不同,重载分辨率也不同。
猜你喜欢
  • 1970-01-01
  • 2014-03-16
  • 1970-01-01
  • 2012-09-29
  • 1970-01-01
  • 2016-11-27
  • 2017-06-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多