如何从监视列表中隐藏一些类公共属性?

2022-07-19 00:00:00 class templates c++ c++builder declspec

我仍然在使用BDS 2006(Turbo Explorer C++),升级仍然不是一个选项。我有一个问题,在调试一些更高级的模板/类时,这些模板/类包含以下属性:

__declspec( property (get=???, put=???) ) ??? ???;

作为成员变量处理,使监视列表和调试器在它们太多时变得疯狂。结果是在断点和跟踪期间大大减慢,并且当此类类在监视列表中时,IDE本身偶尔冻结(唯一的补救方法是使用Windows任务管理器结束bds.exe进程树)。

所以我的问题是:

Q1:如何隐藏这些属性,使其在监视列表中不可见,同时仍保持public

我认为可能有某种宏观或指令来实现这一点。将这些设置为非public不是一个选项。监视列表像处理成员变量而不是函数一样处理此属性。

这里有一个小示例(从我的GLSL数学中摘录vec2类):

//---------------------------------------------------------------------------
template <class T> class _vec2
    {
public:
    T dat[2];
    _vec2(T _x,T _y) { x=_x; y=_y; }
    _vec2() { for (int i=0;i<2;i++) dat[i]=0; }
    _vec2(const _vec2& a) { *this=a; }
    ~_vec2() {}
    // 1D
    T get_x() { return dat[0]; } void set_x(T q) { dat[0]=q; }
    T get_y() { return dat[1]; } void set_y(T q) { dat[1]=q; }
    __declspec( property (get=get_x, put=set_x) ) T x;
    __declspec( property (get=get_y, put=set_y) ) T y;
    __declspec( property (get=get_x, put=set_x) ) T r;
    __declspec( property (get=get_y, put=set_y) ) T g;
    __declspec( property (get=get_x, put=set_x) ) T s;
    __declspec( property (get=get_y, put=set_y) ) T t;

    // 2D
    _vec2<T> get_xy() { return _vec2<T>(x,y); } void set_xy(_vec2<T> q) { x=q.x; y=q.y; }
    _vec2<T> get_yx() { return _vec2<T>(y,x); } void set_yx(_vec2<T> q) { y=q.x; x=q.y; }
    __declspec( property (get=get_xy, put=set_xy) ) _vec2<T> xy;
    __declspec( property (get=get_xy, put=set_xy) ) _vec2<T> xg;
    __declspec( property (get=get_xy, put=set_xy) ) _vec2<T> xt;
    __declspec( property (get=get_yx, put=set_yx) ) _vec2<T> yx;
    __declspec( property (get=get_yx, put=set_yx) ) _vec2<T> yr;
    __declspec( property (get=get_yx, put=set_yx) ) _vec2<T> ys;
    __declspec( property (get=get_xy, put=set_xy) ) _vec2<T> ry;
    __declspec( property (get=get_xy, put=set_xy) ) _vec2<T> rg;
    __declspec( property (get=get_xy, put=set_xy) ) _vec2<T> rt;
    __declspec( property (get=get_yx, put=set_yx) ) _vec2<T> gx;
    __declspec( property (get=get_yx, put=set_yx) ) _vec2<T> gr;
    __declspec( property (get=get_yx, put=set_yx) ) _vec2<T> gs;
    __declspec( property (get=get_xy, put=set_xy) ) _vec2<T> sy;
    __declspec( property (get=get_xy, put=set_xy) ) _vec2<T> sg;
    __declspec( property (get=get_xy, put=set_xy) ) _vec2<T> st;
    __declspec( property (get=get_yx, put=set_yx) ) _vec2<T> tx;
    __declspec( property (get=get_yx, put=set_yx) ) _vec2<T> tr;
    __declspec( property (get=get_yx, put=set_yx) ) _vec2<T> ts;

    // operators
    _vec2* operator = (const _vec2 &a) { for (int i=0;i<2;i++) dat[i]=a.dat[i]; return this; }                              // =a
    T& operator [](const int i)     { return dat[i]; }                                                                      // a[i]
    _vec2<T> operator + ()          { return *this; }                                                                       // +a
    _vec2<T> operator - ()          { _vec2<T> q;       for (int i=0;i<2;i++) q.dat[i]=      -dat[i];           return q; } // -a
    _vec2<T> operator ++ ()         {                   for (int i=0;i<2;i++)                 dat[i]++;     return *this; } // ++a
    _vec2<T> operator -- ()         {                   for (int i=0;i<2;i++)                 dat[i]--;     return *this; } // --a
    _vec2<T> operator ++ (int)      { _vec2<T> q=*this; for (int i=0;i<2;i++)                 dat[i]++;         return q; } // a++
    _vec2<T> operator -- (int)      { _vec2<T> q=*this; for (int i=0;i<2;i++)                 dat[i]--;         return q; } // a--

    _vec2<T> operator + (_vec2<T>&v){ _vec2<T> q;       for (int i=0;i<2;i++) q.dat[i]=       dat[i]+v.dat[i];  return q; } // a+b
    _vec2<T> operator - (_vec2<T>&v){ _vec2<T> q;       for (int i=0;i<2;i++) q.dat[i]=       dat[i]-v.dat[i];  return q; } // a-b
    _vec2<T> operator * (_vec2<T>&v){ _vec2<T> q;       for (int i=0;i<2;i++) q.dat[i]=       dat[i]*v.dat[i];  return q; } // a*b
    _vec2<T> operator / (_vec2<T>&v){ _vec2<T> q;       for (int i=0;i<2;i++) q.dat[i]=divide(dat[i],v.dat[i]); return q; } // a/b

    _vec2<T> operator + (const T &c){ _vec2<T> q;       for (int i=0;i<2;i++) q.dat[i]=dat[i]+c;                return q; } // a+c
    _vec2<T> operator - (const T &c){ _vec2<T> q;       for (int i=0;i<2;i++) q.dat[i]=dat[i]-c;                return q; } // a-c
    _vec2<T> operator * (const T &c){ _vec2<T> q;       for (int i=0;i<2;i++) q.dat[i]=dat[i]*c;                return q; } // a*c
    _vec2<T> operator / (const T &c){ _vec2<T> q;       for (int i=0;i<2;i++) q.dat[i]=divide(dat[i],c);        return q; } // a/c

    _vec2<T> operator +=(_vec2<T>&v){ this[0]=this[0]+v; return *this; };
    _vec2<T> operator -=(_vec2<T>&v){ this[0]=this[0]-v; return *this; };
    _vec2<T> operator *=(_vec2<T>&v){ this[0]=this[0]*v; return *this; };
    _vec2<T> operator /=(_vec2<T>&v){ this[0]=this[0]/v; return *this; };

    _vec2<T> operator +=(const T &c){ this[0]=this[0]+c; return *this; };
    _vec2<T> operator -=(const T &c){ this[0]=this[0]-c; return *this; };
    _vec2<T> operator *=(const T &c){ this[0]=this[0]*c; return *this; };
    _vec2<T> operator /=(const T &c){ this[0]=this[0]/c; return *this; };
    // members
    int length() { return 2; }  // dimensions
    };
//---------------------------------------------------------------------------
template <class T> T min(const T &a,const T &b)  { if (a<b) return a; return b; }
template <class T> T max(const T &a,const T &b)  { if (a>b) return a; return b; }
double abs(const double &a) { if (a<0.0) return -a; return a; }
//---------------------------------------------------------------------------
// get vector size
template <class T> double   length   (const _vec2<T> &v)  { double l=0.0; for (int i=0;i<2;i++) l+=v.dat[i]*v.dat[i]; return sqrt(l); }
// get vector size^2
template <class T> double   length2  (const _vec2<T> &v)  { double l=0.0; for (int i=0;i<2;i++) l+=v.dat[i]*v.dat[i]; return l; }
// get unit vector
template <class T> _vec2<T> normalize(const _vec2<T> &v)  { _vec2<T> q=v; double l=divide(1.0,length(v)); for (int i=0;i<2;i++) q.dat[i]*=l; return q; }
// get dot product
template <class T>       T  dot  (const _vec2<T> &v1,const _vec2<T> &v2) { T l=0.0; for (int i=0;i<2;i++) l+=v1.dat[i]*v2.dat[i]; return l; }
// c+v
template <class T> _vec2<T> operator + (double c,_vec2<T>&v){ _vec2<T> q; for (int i=0;i<2;i++) q.dat[i]=c+v.dat[i];  return q; }
// c-v
template <class T> _vec2<T> operator - (double c,_vec2<T>&v){ _vec2<T> q; for (int i=0;i<2;i++) q.dat[i]=c-v.dat[i];  return q; }
// c*v
template <class T> _vec2<T> operator * (double c,_vec2<T>&v){ _vec2<T> q; for (int i=0;i<2;i++) q.dat[i]=c*v.dat[i];  return q; }
//---------------------------------------------------------------------------
typedef _vec2<float >  vec2;
typedef _vec2<double> dvec2;
typedef _vec2<bool  > bvec2;
typedef _vec2<int   > ivec2;
typedef _vec2<DWORD > uvec2;
//---------------------------------------------------------------------------
vec2 GLSL_math_test2;   // ensure that template code is compiled/linked
//---------------------------------------------------------------------------

用法:

vec2 a;
a=vec2(0.1,0.2);
a+=a;         // <<- here breakpoint

监视列表:

[+]a    { { 0.1, 0.2 }, ????, ????, ????, ????, ????, ????, ????, ????, ????, ????, ????, ????, ????, ????, ... }

如果我打开a[+]子菜单,它会显示:

[-]a    { { 0.1, 0.2 }, ????, ????, ????, ????, ????, ????, ????, ????, ????, ????, ????, ????, ????, ????, ... }
  [+]dat {0.1,0.2}

所以没有更多的财产...这可能暗示监视列表窗口可能以某种方式可配置为使用某些隐藏选项来实现这一点。

这个小的单个类实例不是大问题,但当我更改为以下内容时:

vec2 a[20];
a[0]=vec2(0.1,0.2);
a[1]=a[0]; // <<- here breakpoint

再一次观察a,IDE在断点处立即停滞,我的下一步可能只有Kill进程。现在设想一个更大的项目,其中有更多的类和动态列表……此类项目无法再正确调试(或根本无法调试)。

PS。BDS 2006中的IDE冻结是一个众所周知的错误。如果监视列表显示的数据太多(它可能只是一个很长的字符串,没什么特别的),IDE就会减慢并冻结(根据显示的数据量和执行F7/F8的步骤)。

Edit1:

作为一种解决办法,我添加了配置宏来禁用对不需要的应用程序的大部分切换。下面是一个简单类的监视列表屏幕截图示例:

但有很多东西需要搅动,甚至像这样简单的东西都已经超出了手表窗口的极限。

Edit2:进度更新

#pragma中没有一条语句看起来很有希望。从2010年开始,Debugger_Visualizers已经添加到IDE中,它可以解决这个问题,但我仍然使用较旧的版本,目前不能进行移植。

阵列的当前解决方法:

vec2 a[20];
a[0]=vec2(0.1,0.2);
a[1]=a[0]; // <<- here breakpoint

观看:

| a[0].dat,20 | { 0.1, 0.2 }, { 0.1, 0.2 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } |

因此,对于单数实例,请使用vec2::dat成员而不是vec2。对于使用数组监视格式a[start index].dat,number of items而不是a的数组。

这是快速的(不冻结),但是由于硬编码的大小(必须是硬编码的数字,没有表达式或变量),其潜在的访问冲突。这仍然不能用于更复杂的struct/classes整体(如多边形、网格),但至少现在有一些用于数组的调试选项。


解决方案

如果要更改对象在调试环境中的可视化方式,可以尝试使用native visualisers。我很愿意给你一些信息,但考虑到这个主题的规模,也许你首先想先看一看,然后再决定是否使用这项技术。

相关文章