debugging 无法序列化和设置容器类的LogggerDisplayAttribute

vptzau2j  于 2023-10-24  发布在  其他
关注(0)|答案(1)|浏览(95)

我正在为一个带有预分配内存块的自定义内存管理器的项目做一个矢量实现,我已经成功地使上述矢量执行基本功能,如push_back,erase,reserve,开始()和end(),以允许每个循环,等等,但遗憾的是(和预期的),悬停的东西只是显示指向的第一个对象,没有其他东西。
虽然不是严格必要的,但是能够将这个实现当作常规的std::vector来悬停仍然是非常有帮助的。这是可能做到的吗?我发现了一些关于visual studio中变量的自定义属性的页面,但是没有真正实现它们。
我已经提供了代码,因为它目前站在底部的问题。唯一重要的部分,这个问题的代码,我认为至少,是顶部。当试图编译,我得到三个错误:E2020 -托管nullptr类型不能在这里使用,C2337 - 'Serializable':属性找不到,和C2337'NonSerialized':找不到属性(每个成员变量都有这个属性)。如果我删除类声明上方的[Serializable],我会得到C3115 'System::Diagnostics::LogggerDisplayAttribute':此属性在'ML_Vector'上不允许,而不是Serializable错误。
我已经在公共语言运行时支持字段中将/clr添加到项目中。
这似乎是一个相当模糊的主题,因为我还没有找到任何解释这个主题的视频,也不知道从这里开始。

#pragma once
#include "MemLib\MemLib.hpp"
#include <cinttypes>
#include <stdexcept>

#ifdef _DEBUG
using namespace System::Diagnostics;
#endif // _DEBUG
template<typename T>
#ifdef _DEBUG
[Serializable]
[DebuggerDisplayAttribute("Size={m_size}")] // Supposed to act as a proof of concept
struct ML_Vector
{
private:
    // Pool pointer to internal data
    [NonSerialized]
    PoolPointer<T> m_data;
    // Due to our memory usage restriction, a size larger than 2^30 would be guaranteed to exceed memory limits
    [NonSerialized]
    uint32_t m_size = 0;
    // Due to our memory usage restriction, a size larger than 2^30 would be guaranteed to exceed memory limits
    [NonSerialized]
    uint32_t m_capacity = 0;
    // size of the internal type
    [NonSerialized]
    uint16_t m_tSize = 0;
#else // _DEBUG
struct ML_Vector
{
private:
    // Pool pointer to internal data
    PoolPointer<T> m_data;
    // Due to our memory usage restriction, a size larger than 2^30 would be guaranteed to exceed memory limits
    uint32_t m_size = 0;
    // Due to our memory usage restriction, a size larger than 2^30 would be guaranteed to exceed memory limits
    uint32_t m_capacity = 0;
    // size of the internal type
    uint16_t m_tSize = 0;
#endif

public:
    T* begin() const
    {
        return &(m_data[0]);
    }

    T* end() const
    {
        return &(m_data[m_size]);
    }

    const uint32_t& size() const
    {
        return m_size;
    }

    const PoolPointer<T>& data() const
    {
        return m_data;
    }

    // Reserve a new capacity for the vector
    uint32_t reserve(const uint32_t& capacity)
    {
        if (capacity < m_capacity)
        {
            throw std::invalid_argument("Capacity too small! ML_Vector.reserve() cannot be called to reduce the capacity of the vector!");
            std::terminate();
        }

        // Provide a temporary copy of the data
        T* temp = (T*)MemLib::spush(m_capacity * m_tSize);
        std::memcpy(temp, &(*m_data), m_capacity * m_tSize);

        // Free the old pool pointer and allocate a new one
        MemLib::pfree(m_data);
        m_data = MemLib::palloc(capacity);

        // Copy the data over to the new location and pop the temp from the stack
        std::memcpy(&(*m_data), temp, m_capacity * m_tSize);
        MemLib::spop();

        // Inform the new capacity
        return m_capacity = capacity;
    };

    // Clear the vector
    void clear()
    {
        // No need to actually clear data, just setting the size to 0 is enough
        m_size = 0;
    }

    // Push an item into the back of the vector, returns the index of that item
    uint32_t push_back(const T& item)
    {
        // if the capacity of the vector is less than the size of the vector, reserve a larger chunk of memory
        if (m_capacity <= m_size + 1)
        {
            reserve(m_capacity * 2);
        }

        // Set data at location
        m_data[m_size] = item;

        // Return the index of the newly pushed object
        return m_size++;
    };

    // Remove an item in the vecotr by index
    // This operation is much slower than pop_back, and should not be used if pop_back could simply be used instead
    uint32_t erase(const uint32_t& idx)
    {
        if (idx < 0 || m_size <= idx)
        {
            throw std::out_of_range("Index provided for ML_Vector is out of range!");
            std::terminate();
        }

        // Overwrite
        std::memcpy(&(m_data[idx]), &(m_data[idx + 1]), (m_size - idx) * m_tSize);

        return --m_size;
    };

    // Pop and return the back most item of the vector
    T pop_back()
    {
        if (m_size <= 0)
        {
            throw std::out_of_range("Out of range exception for ML_Vector at pop_back(), vector already empty!");
            std::terminate();
        }

        // No need to actually remove the data in any "real" way, just mark it as empty
        return m_data[--m_size];
    };

    T& operator*()
    {
        return (*m_data);
    };

    T& operator[](const uint32_t& idx)
    {
        if (idx < 0 || m_size <= idx)
        {
            throw std::out_of_range("Index provided for ML_Vector is out of range!");
            std::terminate();
        }

        return m_data[idx];
    };

    ML_Vector& operator=(const ML_Vector& other)
    {
        if (false == m_data.IsNullptr())
            MemLib::pfree(m_data);
        m_data = other.m_data;
        m_capacity = other.m_capacity;
        m_size = other.m_size;
        m_tSize = other.m_tSize;

        return *this;
    }

    // Initiate an ML_Vector<T> with a number of T objects, can be called as such to emulate normal C++ style coding
    // ML_Vector<T>() = { args };
    template<typename... Types>
    ML_Vector(Types... args)
    {
        // Set capacity
        m_capacity = sizeof...(args);

        // Allocate to memory pool
        if (false == m_data.IsNullptr())
            MemLib::pfree(m_data);
        m_data = MemLib::palloc(m_capacity);

        // Set the individual item size
        m_tSize = sizeof(T);

        // Set items
        for (auto item : { args... } )
        {
            /*T test = item;*/
            push_back(item);
            //ZeroMemory(item, sizeof(item));
        }
    };
};
8zzbczxx

8zzbczxx1#

我通过简单地放弃System::Diagnostics并找到.natvis文件来解决这个问题。我在项目中添加了一个(添加新项-> Visual C++ -> Utility -> Logger Visualization File)。
下面的代码目前运行得很好,至少让我们看到了双指针背后的内部结构。

<?xml version="1.0" encoding="utf-8"?> 
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="ML_Vector&lt;*&gt;">
    <!--<DisplayString>{{ size={_Mylast - _Myfirst} }}</DisplayString>-->
    <Expand>
        <Item Name="[Size]" ExcludeView="simple">m_size</Item>
        <Item Name="[capacity]" ExcludeView="simple">m_capacity</Item>
        <ArrayItems>
            <Size>m_size</Size>
            <ValuePointer>*(m_data.m_pp)</ValuePointer>
        </ArrayItems>
    </Expand>
</Type>

相关问题