1

I am still using BDS2006 (Turbo explorer C++) and upgrading is still not an option. I have a problem that while debugging some of more advanced template/classes containing properties like:

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

are handled as member variables making the watch list and debugger going nuts if there are too many of them. The result is big slow down during breakpoints and traces and occasional (very often) freezing of the IDE itself when such class is in the watch list (with the only remedy to use windows task manager to end bds.exe process tree).

SO my question is:

Q1: How to hide these properties so they are not visible in watch list while they still remain public?

I think there might be some kind of macro or directive for this. Making those not public is not an option. The watch list handles this properties like member variables instead of functions.

Here small example (extracted vec2 class from my GLSL math):

//---------------------------------------------------------------------------
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
//---------------------------------------------------------------------------

usage:

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

Watch list:

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

if I open the [+] sub-menu of a watch it displays:

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

so no more properties... which might hint the watch list window might be somehow configurable to achieve this with some hidden option too.

This small single class instance is not a big problem but when I change to something like this:

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

and watching a again the IDE froze instantly on the breakpoint and only Kill process is my next possible step. Now imagine bigger project where there are much more classes and dynamic lists of those ... Such project is non possible to debug properly (or at all) anymore.

PS. the freezing of IDE in BDS2006 is a well known bug. If the watch list is showing too much data (it can be just a long string nothing fancy) the IDE slows down and freeze (according of how much data is displayed and how many steps F7/F8 are done).

Edit1:

As a workaround I added configuration macros that disable most of the swizzling for Apps that does not need it. Here a watch list screenshot example for a simple class:

Watch list

But there is a lot of stuff that needs the swizzling and even simple stuff like this is already stretching the limits of the watch window.

Edit2: progress update

None of the #pragma statements looks promising. From 2010 the Debugger_Visualizers has been added to the IDE which could solve this however I am still on older version and porting is not an option for now.

current workaround for arrays:

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

watch:

| 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 } |

so for singular instances use vec2::dat member instead of vec2. For arrays using array watch format a[start index].dat,number of items instead of a.

This is fast (does not freeze) however its potentionaly access violating due to hard-coded size (which must be hardcoded number no expressions or variables). This still can not be used for whole struct/classes that are more complex (like polygons,meshes) but at least now there is some debugging option for arrays.

Spektre
  • 49,595
  • 11
  • 110
  • 380
  • Well, don't abuse of complex properties.It is quite suspicious to have also 20 properties of your own types. **The code is even more suspicious since all properties uses the same 2 getters** (that is `get_xy` and `get_yx` and same thing for getter). At that point, you could have only 2 properties which would be much faster. – Phil1970 Jul 03 '20 at 12:38
  • If you have such an old compiler, do you have an even older computer? Also your code depends on non standard extension so it might be a good idea to stop using them as soon as possible so that you would be able to use a moder compiler. In 2020, all C++ software development should use C++ 17. You are not yet even at C++ 11! So you are not using modern C++. – Phil1970 Jul 03 '20 at 12:52
  • 1
    @Phil1970 1. the getters and setters mimic GLSL `vec` type properties nothing suspicious about that (it provides element swizzling with the same functionality as in GLSL) ... its just the simplest 2D example full code goes up to 4D ... 2. as mentioned in the question porting to newer or even incompatible compiler is not an option. What do you mean by `non standard extension` ? Newer C++ standards are often not adding anything usable (in usual daily programming tasks) apart of problems with porting to different non x86/x64/ARM platforms. Anyway your comments does not address my question... – Spektre Jul 03 '20 at 14:58
  • @Phil1970 this is more C++Builder IDE specific question than a coding one ... – Spektre Jul 03 '20 at 15:00
  • Given that it is a well known bug and it seems that C++ builder lack a way to customize watch display, I think the only work-around is to stop using them (or at least not in a recursive way). `property` is not part of standard C++ but at least Microsoft compiler has them (https://learn.microsoft.com/en-us/cpp/cpp/property-cpp?view=vs-2019) and they are tagged as Microsoft specific. – Phil1970 Jul 03 '20 at 22:39

2 Answers2

1

When you want to alter the way objects are visualised in a debugging environment, you might try to use native visualisers. I'm willing to give you some information but seen the size of this subject, maybe you first want to have a first look before you decide whether or not to use this technology.

Dominique
  • 16,450
  • 15
  • 56
  • 112
  • BDS2006 is not MSVC++ IDE, will it work in Borland/Embarcadero environments? – Spektre Jul 07 '20 at 14:50
  • I'm sorry, I don't know this. I've been working with Visual Studio where I have been working quite frequently with native visualisers. As far as your IDE is concerned, I have no idea, but you might use this as a starting point for your search (or question to the Embarcadero technical support). – Dominique Jul 07 '20 at 15:38
  • I just found this topic [Debugger Visualizers](http://docwiki.embarcadero.com/RADStudio/Seattle/en/Debugger_Visualizers) its for much newer version of Borland/Embarcadero IDE than I am using so I need to inspect if it works for me too... – Spektre Jul 10 '20 at 08:40
  • @Spektre: glad to see you have found a starting point. Can you upgrade your IDE to the desired version and inform us of the results? – Dominique Jul 10 '20 at 08:46
  • Unfortunately no I can not upgrade yet ... that would be too expensive (not just the IDE itself but also the related stuff like drivers, licences etc ..) and needed a lot of work porting apps to new compiler/IDE ... last upgrade take around a year and there is simply not enough time and man power to spare right now... It looks like they added this functionality in 2010 so it will not work in BDS2006 :( how ever in the video is mentioned some old way ... anyway +1 for a possible direction to look for – Spektre Jul 10 '20 at 08:59
  • I found painful workaround for arrays, but still no universal solution ... added edit2 ... – Spektre Jul 10 '20 at 09:55
  • As usual I have not got a working answer (I usually end up answering my own questions) yet but the bounty was about to expire and as your answer is closer to what I need and the only one that could work on BCB/BDS/RAD you got the reward ... – Spektre Jul 13 '20 at 06:55
0

You can disable a watch expression/variable by right mouse click in the Watch Window and uncheck the checkbox in front of any variables. This will disable them from the debugger but they will still stay in the watch window.

You can also "group" watch expressions/variables and then enable/disable all of the watches in a group to turn on/off display of watch values - this can increase debugger speed.

http://docwiki.embarcadero.com/RADStudio/Sydney/en/Watch_List_Window

Disable Watch

Disables a watch expression and so that it is not monitored as you step through or run your program. The watch settings remain defined. Disabling watches improves debugger performance.

You can also decide which symbol tables to include for debugging - check out

http://docwiki.embarcadero.com/RADStudio/Sydney/en/Debugger_Symbol_Tables

user186876
  • 191
  • 5
  • individual enabling disabling is not an option for structs and classes as they are grouped together and first line contains everything so it will not solve anything as disabling its first entry of a class/struct will hide everything... I never used debug symbol tables before do you have an example? I can add a path but it does not do anything and can not edit in anything ... does it expect some filetype? what format? My bet its just selects what exe/obj/dll stuff to add in the list of watchable variables and not what properties ... – Spektre Jul 07 '20 at 07:23
  • Was hoping for a macro that would be typed into source code directly something similar how you can enable/disable specific warnings for parts of code like [#pragma warn ...](https://stackoverflow.com/a/56980191/2521214) statements – Spektre Jul 07 '20 at 07:35