为啥 nvcc 失败允许将 T * 类型的指针转​​换为 void *?

Posted

技术标签:

【中文标题】为啥 nvcc 失败允许将 T * 类型的指针转​​换为 void *?【英文标题】:Why does nvcc fail allow casting a pointer of type T * to void *?为什么 nvcc 失败允许将 T * 类型的指针转​​换为 void *? 【发布时间】:2013-02-19 12:49:04 【问题描述】:

使用以下琐碎的删除器

struct CudaDeleter void operator()(void * ptr)  cudaFree( ptr );  ;

在使用 nvcc 编译的代码中使用删除器时出现以下错误。相同的删除器适用于 vs2012 编译器

warning : "std::unique_ptr<_Ty, _Dx>::unique_ptr(
const std::unique_ptr<_Ty, _Dx>::_Myt &)
[with _Ty=const int, _Dx=cuda::CudaDeleter]"

error : function "cuda::CudaDeleter::operator()"
cannot be called with the given argument list

warning : "std::unique_ptr<_Ty, _Dx>::unique_ptr(
const std::unique_ptr<_Ty, _Dx>::_Myt &)
[with _Ty=float, _Dx=cuda::CudaDeleter]"

@talonmies:智能指针仅使用此函数构造

template <typename T>
std::unique_ptr<T, CudaDeleter> make_unique(size_t size)

    void * pMemory = nullptr;
    check( cudaMalloc(&pMemory, size) );
    return std::unique_ptr<T, CudaDeleter>( static_cast<T*>(pMemory) );

【问题讨论】:

nvcc 编译器似乎有太多这些奇怪的怪癖,还有一个是不支持 range-for,模板失败时无法给出正确的错误......最好编译为使用 nvcc 编译器尽可能少的代码? 这是一个非常不言自明的错误 - 您正在将 C++ 智能指针传递给删除函数,它需要 void *。不要责怪编译器..... 不,我在构造智能指针时将删除函数传递给智能指针 nvcc是否支持c++11的unique_ptr?使用 unique_ptr 时,您可能必须为 nvcc/gcc 启用 c++11 功能。另一方面,void* 是 c 风格的代码。 template&lt;class T&gt; struct CudaDeleter void operator()(T* ptr)... 可能是 unique_ptr 更好的删除函子。 问题是 nvcc 不是编译器。它不编译代码,也不编译此代码,主机编译器是(在这种情况下是 vs2012)。它所做的是引导编译并设置编译器参数。编译器选项可能会禁用 c++11 支持,但这就是可能发生的一切。 【参考方案1】:

以下内容对我有用。试试下面的独立代码,如果它可以工作,那么你需要确定与你的代码的区别,如果没有,那么你的设置有一些不同。

#include <iostream>
#include <memory>

struct CudaDeleter

    void operator()(void *p)
    
        std::cout << "Free..." << std::endl;
        cudaError_t res = cudaFree(p);
        if (res != cudaSuccess)
        
            std::cout << "Error freeing: " << cudaGetErrorString(res) << std::endl;
        
    
;

template <typename T>
std::unique_ptr<T, CudaDeleter> make_unique(size_t size)

    void *pMemory = nullptr;
    std::cout << "Allocate..." << std::endl;
    cudaError_t res = cudaMalloc(&pMemory, size);
    if (res != cudaSuccess)
    
        std::cout << "Error allocating pMemory: " << cudaGetErrorString(res) << std::endl;
        throw;
    
    return std::unique_ptr<T, CudaDeleter>(static_cast<T*>(pMemory));


int main(void)

    
        std::cout << "Create..." << std::endl;
        std::unique_ptr<float, CudaDeleter> x = make_unique<float>(100*sizeof(float));
        std::cout << "Destroy..." << std::endl;
    
    std::cout << "Done." << std::endl;

【讨论】:

【参考方案2】:

我找到了我遇到的问题,最后这是我的错误

不是任何 T * 都不能转换成 void * 而是 const T * 不能转换成 void *。

另外一个指向 const 的指针不能被 cudaFree 释放,这意味着 Eric 的建议

template<class T> struct CudaDeleter void operator()(T* ptr)...

不会工作。

这样的东西会起作用

template <typename T>
std::unique_ptr<typename std::remove_const<T>::type, CudaDeleter> make_unique(size_t size)

    typename std::remove_const<T>::type * pMemory = nullptr;
    check( cudaMalloc(&pMemory, size) );
    return std::unique_ptr<typename std::remove_const<T>::type, CudaDeleter>( pMemory );

【讨论】:

以上是关于为啥 nvcc 失败允许将 T * 类型的指针转​​换为 void *?的主要内容,如果未能解决你的问题,请参考以下文章

为啥常量整数指针指向允许的非常量整数?

为啥C ++允许将指向基对象的指针转换为派生类的指针[重复]

为啥 C# 允许将泛型数组与所有类型的模式进行匹配?

为啥 nvcc 无法使用 boost::spirit 编译 CUDA 文件?

为啥新的 `Pick<T, K extends keyof T>` 类型允许在 React 的 `setState()` 中使用 `K` 的子集?

为啥 Typescript 允许将 `a: 1, b: 2` 分配给类型 `a: any | b:任何`? [复制]