如何确定对象是否具有堆分配成员?

时间:2019-06-30 10:20:06

标签: c++ class templates c++17 member

有没有一种方法可以确定对象在堆上是否具有至少一个成员?

我试图将std::stringstd::vectorstd::list之类的对象(主要是容器)与所有其他类型(不幸的是,即使只有单个元素的容器也位于我的容器中) “兴趣范围”)

我正在尝试执行以下操作:

struct foo
{
private:
    int * _ptr;

public:
    foo() : _ptr(new int) {};
    ~foo() { delete _ptr; };
};

struct bar
{
private:
    int val;
};

template <typename T>
void func(T val)
{
    if constexpr (std::is_class_v<T>)
    {
        std::cout << std::setw(20) << typeid(T).name() << " is a class type." << std::endl;
        if (/* determine if foo has any heap allocations */)
        {
            // Do something #1.
            std::cout << std::setw(20) << typeid(T).name() << " does allocate on heap." << std::endl;
        }
        else
        {
            // Do something #2.
            std::cout << std::setw(20) << typeid(T).name() << " does NOT allocate on heap." << std::endl;
        }
    }
    else
    {
        // Do something #3.
        std::cout << std::setw(20) << typeid(T).name() << " is NOT a class type." << std::endl;
    }
}

int main()
{
    func(foo()); // foo does allocate on heap
    cout << endl;

    func(bar()); // bar does NOT allocate on heap
    cout << endl;
};

foobar只是示例,函数func()的执行功能与控制台的cout有点不同。

5 个答案:

答案 0 :(得分:4)

  

这是XY问题...我正在尝试编写一个散列函数,它将   注意用户定义的键类型是否在数组上存储任何数据   (就像std :: string`一样)。我相当有能力创建一个通用的   具有任何类型的哈希函数,但是如果该类型具有数组(   指向某些存储数据的指针,问题变得非常棘手   (指向动态数组的指针会在运行时更改,相同的键位于   不同的时间会产生不同的哈希值)

请注意,某些结构/类类型具有内部未初始化的填充,这可能会使您的哈希函数无法正常工作。

否则,"{"timestamp":"2019-06-30T08:45:26.461+0000","status":500,"error":"Internal Server Error","message":"Current request is not a multipart request","path":"/consumeFiles"}"将是一个好的开始。

答案 1 :(得分:3)

正如其他人在评论中指出的那样,无法区分指针是否指向动态分配的指针。另一方面,C ++标准<type_traits>提供的类型特征如

,依此类推。看看这些链接是否适合您的实际问题。


话虽这么说,为什么不能用告诉您所需信息的成员函数来解决呢?

例如:

struct foo
{
public:
    bool isHeapAllocated() const noexcept { return true; }
};

struct bar
{
public:
    bool isHeapAllocated() const noexcept { return false; }
};

然后只需调用函数:

template <typename T> void func(T val)
{
    if constexpr (std::is_class_v<T>)
    {
        if (val.isHeapAllocated()) { 
            // Do something #1.
        }
        else
        {
            // Do something #2.
        }
    }
    else
    {
        // Do something #3.
    }
}

答案 2 :(得分:3)

虽然我可以肯定其他答案是正确的,但当他们说您不应该试图确定某个对象是驻留在堆还是堆栈上时,我对此表示不同意。

>

以下示例使用Windows(每个操作系统的操作步骤都不一样!)

... </Columns>
...
<HeaderStyle ForeColor="Red" />
<SelectedRowStyle ...
</asp:GridView> ...

此函数将确定给定地址是否在堆上。这里是测试程序:

#include <Windows.h>
bool isAddressOnHeap(void* address) {
    bool returnval = 0;
    PROCESS_HEAP_ENTRY entry;
    HANDLE procHeap = GetProcessHeap();
    if (procHeap == NULL) {
        std::cerr << "Failed to retrieve Heap.\n";
        return -1;
    }

    if (HeapLock(procHeap) == FALSE) {
        std::cerr << "Failed to lock heap.\n";
        return -1;
    }

    entry.lpData = NULL;
    if (HeapWalk(procHeap, &entry) != 0) {
        if (entry.wFlags & PROCESS_HEAP_REGION) {
            std::cout << "Function succeeded. The heap begins at " << (void*)entry.Region.lpFirstBlock << " and ends at " << (void*)entry.Region.lpLastBlock << "\n";
            if (address >= (void*)entry.Region.lpFirstBlock && address <= (void*)entry.Region.lpLastBlock) 
                returnval = 1;
        }
    }

    if (HeapUnlock(procHeap) == FALSE) {
        std::cerr << "Failed to unlock heap.\n";
        return -1;
    }
    return returnval;
}

程序在我的机器上返回以下内容:

int main()
{
    int i = 1;
    std::cout << "Address of i on Stack: " << (void*)&i << "\n";


    int* j = new int;
    *j = 1;
    std::cout << "Address of j on Heap: " << (void*)j << "\n";

    int* k = (int*)malloc(sizeof(int));
    *k = 1;
    std::cout << "Address of k on Heap: " << (void*)k << "\n";


    std::cout << "is i on Heap?: " << isAddressOnHeap(&i) << "\n";
    std::cout << "is j on Heap?: " << isAddressOnHeap(j) << "\n";
    std::cout << "is k on Heap?: " << isAddressOnHeap(k) << "\n";

    delete j;
    free(k);
    return 0;
}

您可以了解有关此代码如何在Microsoft's website上工作的更多信息。

在Linux计算机上,似乎有similar ways可以做到这一点。

但是作为最后的警告:这个答案只是概念的证明!

答案 3 :(得分:2)

  

我试图区分“以数组为成员的类类型”和“不以数组为成员的类类型”。

您需要查看代码,因此需要将函数的路径传递到源代码,并且需要对其进行解析。

答案 4 :(得分:1)

唯一确定的方法是添加所需的机制来处理每种类型,并根据需要添加单个对象。

以下是任何理智的类型的良好起点(遵守零/三/五的规则):

template <class T>
constexpr auto owns_no_dynamic_memory(T const& x) noexcept {
    if constexpr (std::is_trivially_copyable_v<T>
    || std::is_trivially_move_constructible_v<T>
    || std::is_trivially_copy_assignable_v<T>
    || std::is_trivially_move_assignable_v<T>
    || std::is_trivially_destructible_v<T>)
        return std::true_type();
    else
        return false;
}

根据需要添加重载。