Author Topic: non static C++ class objects with interrupt routines  (Read 3062 times)

0 Members and 3 Guests are viewing this topic.

Online gf

  • Super Contributor
  • ***
  • Posts: 1799
  • Country: de
Re: non static C++ class objects with interrupt routines
« Reply #25 on: June 05, 2026, 07:38:29 am »
I would like to use method chaining to also set the led on, so do this instead-

                auto led = GpioPin( led.PA5, led.OUTPUT ).on(); //on() returns *this, so led is assigned to the GpioPin object

looks ok, and may appear to work (led will be on), but that led GpioPin object was on the stack and at the end of the global constructors that stack space was recovered so that led GpioPin object no longer exists, not good (led reference now refers to somewhere on the stack which no longer is valid).

Which reference? The led variable is not a reference here, but a GpioPin object. A bare auto keyword never deduces to a reference type; it always deduces to a value type because reference qualifiers (& and &&) are stripped from the initializer expression's type.

However, the chained method call prevents RVO (Return Value Optimization), meaning the led object cannot be constructed in-place. Instead, it must be copy-constructed from the temporary object. Since that temporary object lives until the end of the full expression (the semicolon), it survives long enough for led to complete its copy-construction. Therefore, no dangling references are left behind.

If the GpioPin constructor would register the this pointer externally (for example, with a hardware interrupt handler), the copy operation becomes dangerous. In that scenario, GpioPin should be made a non-copyable, non-movable and non-assignable class, which will (correctly) cause the expression above to fail at compile time.
« Last Edit: June 05, 2026, 07:59:42 am by gf »
 

Offline paulca

  • Super Contributor
  • ***
  • Posts: 6004
  • Country: gb
Re: non static C++ class objects with interrupt routines
« Reply #26 on: June 05, 2026, 09:42:26 am »
This is an interesting pattern for AVR.

Code: [Select]
class MyClass {
  static MyClass* instance; // Static pointer to hold the instance
  void handleInterrupt();   // Non-static method
public:
  static void isrGlue();    // Static ISR function
};

MyClass* MyClass::instance = nullptr;

void MyClass::isrGlue() {
  if (instance) instance->handleInterrupt();
}

// Usage
MyClass obj;
MyClass::instance = &obj;
attachInterrupt(digitalPinToInterrupt(2), MyClass::isrGlue, CHANGE);

It takes a bit of brain bending as it's self wrapping singleton.  The class is an adapter of itself.

(If you need/want to make it a true singleton pattern, then you make the "instance" private static, the constructor private.  Then provide an "instance()" static method (with synchronisation if MP) which creates the instance only if it doesn't already exist and returns the instance pointer.) - Why?  If there is any chance of someone accidentally or without care adding another instance of "MyClass" at any point.  If this is an invariant, then a full tight singleton pattern is required.  Note:  Just be thankful you are not in a network transactional scope where such "singletons" are distributed singletons and may or may not be single. You can end up with one part of the system seeing a "single instance" and another part seeing a "single instance", but they are not the same instance.  It's just temporally inconsistent.  These are usually not "stopped", but handled after the fact in a similar way that database deadlock detectors kill stuck locks.

https://en.wikipedia.org/wiki/Singleton_pattern
https://en.wikipedia.org/wiki/Adapter_pattern

Also related (in the area): https://en.wikipedia.org/wiki/Delegation_pattern
« Last Edit: June 05, 2026, 09:53:56 am by paulca »
"What could possibly go wrong?"
Current Open Projects:  STM32F411RE+ESP32+TFT for home IoT (NoT) projects.  Child's advent xmas countdown toy.  Digital audio routing board.
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 8299
  • Country: fi
    • My home page and email address
Re: non static C++ class objects with interrupt routines
« Reply #27 on: June 05, 2026, 09:55:41 am »
On an embedded target using ELF-based toolchains, constructors are collected in dedicated sections and run in the C runtime files.  Modifying those you can modify the order of e.g. static variable initialization (typically copying from Flash to RAM) and when constructors are run.

Similarly, assuming this is ARM architecture using GCC or Clang, you can modify your linker scripts and startup sequence to collect closures (function pointers and object instance references) into a section array using an properly sized and aligned struct and __attribute__((section ("CLOSURES"), __used__)) attribute, to run static void class methods that receive the instance as a parameter.  For example:
Code: [Select]
#include <cstdio>

/*
 * Closures, uses ELF sectuin CLOSUREDEFS
*/

#define  MERGE2_(_A, _B)  _A ## _B
#define  MERGE2(_A, _B)   MERGE2_(_A, _B)

// Naturally aligned, two-pointer structure
struct closuredef {
    void (*fun)(void *obj);
    void  *obj;
};

#define  DEFINE_CLOSURE(_class, _instance, _member)                     \
    __attribute__((section ("CLOSUREDEFS"), __used__))                  \
    static const struct closuredef MERGE2(closure_at_, __LINE__) = {    \
        .fun = reinterpret_cast<void (*)(void *)>(_class::_member),     \
        .obj = reinterpret_cast<void *>(&(_instance))                   \
    }

// To ensure there is at least one closure in the array, define a dummy closure
__attribute__((section ("CLOSUREDEFS"), __used__))
static const struct closuredef dummy_closure = { .fun = 0, .obj = 0 };

static void run_closures(void) {
    extern const struct closuredef __start_CLOSUREDEFS[];
    extern const struct closuredef __stop_CLOSUREDEFS[];
    for (const struct closuredef *def = __start_CLOSUREDEFS; def < __stop_CLOSUREDEFS; def++)
        if (def->fun)
            def->fun(def->obj);
}

/*
 * Example classes
*/

class Some {
public:

    static void init(Some *const self) {
        std::printf("init(%p)\n", reinterpret_cast<void *>(self));
        self->foo("pong");
    }

    void foo(const char *msg) {
        if (msg)
            std::printf("foo(\"%s\")\n", msg);
        else
            std::printf("foo()\n");
    }
};

Some  some;

DEFINE_CLOSURE(Some, some, init);

int main(void) {
    std::printf("some is at %p\n", &some);
    run_closures();
    std::printf("Done.\n");
    return 0;
}
Note the DEFINE_CLOSURE(Some, some, init); line that causes Some::init(some) to be called when run_closures() is run.  The order of these closures varies.  You can examine the object code produced to see there is very little overhead.

The standard Linux linker scripts generates __start_SECTIONNAME and __stop_SECTIONNAME symbols for each section thus used, above CLOSUREDEFS, but on embedded targets you need your linker script to generate them using for example
    .rodata {
        . = ALIGN(4);    /* 32-bit alignment */
        *(.rodata)
        *(.rodata*)
        __start_CLOSUREDEFS = .;
        *(CLOSUREDEFS)
        __stop_CLOSUREDEFS = .;
        . = ALIGN(4);
    } > FLASH
or similar.
 

Offline Tation

  • Frequent Contributor
  • **
  • Posts: 275
  • Country: pt
Re: non static C++ class objects with interrupt routines
« Reply #28 on: June 05, 2026, 11:22:02 am »
Both GCC & clang support __attribute__((constructor(priority))), allowing functions or methods to be invoked before main(), also controlling their execution order.
 

Offline gpr

  • Contributor
  • Posts: 43
  • Country: gb
Re: non static C++ class objects with interrupt routines
« Reply #29 on: June 05, 2026, 11:36:41 am »
I think I'll go back to blank constructors and an init function

Take a look at placement new operator in C++. You can split memory allocation and calling constructor. Allocate memory statically with static array of appropriate size and alignment, and call constructor somewhere in main.
 

Online cv007

  • Super Contributor
  • ***
  • Posts: 1049
Re: non static C++ class objects with interrupt routines
« Reply #30 on: June 05, 2026, 05:56:34 pm »
Quote
If the GpioPin constructor would register the this pointer externally (for example, with a hardware interrupt handler), the copy operation becomes dangerous
I did describe it wrong- you will get the stack temporary class object copied into the 'led' object, but assuming its constructor uses the temporary 'this' (stack), when setting the class pointer in a table for irq use it will be pointing to the non-existent temporary class on the stack. The global constructor code will look pretty normal doing the class copy (not that obvious what is happening except for the initial carving out of stack space). Its been a little while, but I think I was doing the method chaining at declaration up until I happened to put a 'this' into the class pointer table, which required some digging to find out what was happening.

https://godbolt.org/z/7x4rM1MY9


Quote
This is an interesting pattern for AVR.
That works fine for a single class instance (only 1 possible peripheral for example). Now do it for something like a uart where you may have 4 of them. You now have to still sort out in some way which instance the isr needs. Various ways to do that, and you could have a class static isr function along with a class static pointer array enough for each peripheral instance (still need to figure out which entry to use), but that starts to look ugly quickly.

For the newer avr you can get the irq number inside the interrupt (by setting to round-robin), so you can do the same as I described for the cortex-m-

class Isr { public: virtual void isr() = 0; };

Isr* table[NUM_OF_IRQS];

Class Uart : Isr {
void isr(){ /*do something*/ }
public: Uart(IRQN irqn){ table[irqn] = this; }
};

void __vector_default() { //override weakly defined __vector_default so we get here from all irqs
    Isr* p{ table[CPUINT.LVL0PRI] };
    if( p ) p->isr();
    else { /* bad interrupt */ }
}

This works fine but probably considered a little heavy for an avr (if you are not into looking at generated asm, you will probably never notice).

The simple way always works, its just that you have a separate set of code to maintain with matched object names (and comment out the unused)-

extern Uart uart0; //defined somewhere else, name must be valid
ISR(USART0_DRE){ uart0.isr(); } //make class isr function always_inline, which may cut down on isr prologue/epilogue
//extern Uart uart1; //unused
//ISR(USART1_DRE){ uart1.isr(); }
//extern Uart uart2; //unused
//ISR(USART2_DRE){ uart2.isr(); }
extern Uart uart3;
ISR(USART3_DRE){ uart3.isr(); }


This can also be done for cortex-m. Nothing wrong in doing this either.

extern Uart uart1;
extern "C" void USART1_IRQHandler(){ uart1.isr(); }
//extern Uart uart2; //unused
//extern "C" void USART2_IRQHandler(){ uart2.isr(); }
 

Online gf

  • Super Contributor
  • ***
  • Posts: 1799
  • Country: de
Re: non static C++ class objects with interrupt routines
« Reply #31 on: June 06, 2026, 11:02:05 am »
Quote
If the GpioPin constructor would register the this pointer externally (for example, with a hardware interrupt handler), the copy operation becomes dangerous
I did describe it wrong- you will get the stack temporary class object copied into the 'led' object, but assuming its constructor uses the temporary 'this' (stack), when setting the class pointer in a table for irq use it will be pointing to the non-existent temporary class on the stack. The global constructor code will look pretty normal doing the class copy (not that obvious what is happening except for the initial carving out of stack space). Its been a little while, but I think I was doing the method chaining at declaration up until I happened to put a 'this' into the class pointer table, which required some digging to find out what was happening.

https://godbolt.org/z/7x4rM1MY9

I would at least prevent copy and move of objects derived from Isr. It's still not 100% bullet proof, but it forces the compiler to flag the issue and bail out right at line 64 where it attempts the copy: https://godbolt.org/z/7vbc33r68

Code: [Select]
                class Isr {
                public:
                    Isr() {}
                    Isr(const Isr&) = delete;
                    Isr& operator=(const Isr&) = delete;
                    virtual void isr()= 0;
                };
 

Online cv007

  • Super Contributor
  • ***
  • Posts: 1049
Re: non static C++ class objects with interrupt routines
« Reply #32 on: June 06, 2026, 04:55:03 pm »
Quote
I would at least prevent copy and move of objects derived from Isr.
That would be a good idea.

After discovery of the problem (using 'this' from a temporary, which led to an exception), I guess I took the approach that no method chaining is to be done in the object declaration but can be done as described in the example (on the next line after the declaration is done). Whether needed for a particular class or not, it makes all usage the same (and I think I would probably stick to the same 'rule' even if the copy/move was prevented by adding the deleted functions in Isr).

What I have now would still allow copy/move, and the method chaining at declaration is probably the only time I end up using a copy and I doubt I have ever used a move for an mcu. But adding the deleted functions to Isr is cheap insurance in case the 'rule' is not followed.
 

Offline Jeroen3

  • Super Contributor
  • ***
  • Posts: 4495
  • Country: nl
  • Embedded Engineer
    • jeroen3.nl
Re: non static C++ class objects with interrupt routines
« Reply #33 on: June 08, 2026, 06:48:14 am »
If it is this difficult to get C++ running, why even bother?
 

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 18835
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: non static C++ class objects with interrupt routines
« Reply #34 on: June 08, 2026, 07:42:45 am »
If it is this difficult to get C++ running, why even bother?

Because it makes life so much easier once it is "running". In my case, it's a case of learning. I have no programming background, unlike most I don't come to micro-controller programming from computer programming or from learning C/C++ on a computer. I started my programming journey on microcontrollers.

For a long time while writing in C I just wished I could do things that, ooh, when I read about C++ I could. No I did not think object oriented but object oriented is the answer to my prayers. Writing classes is kind of what I always wanted. I always struggled to work out where the separation between driver code etc should lie. With classes I am forced to make that decision and it comes more easily.

the ability to make types that are respected by the compiler means that I don't have to write code that checks my function arguments, I simply create an enum type and that type is passed to a function call meaning that the compiler will carry out the check for me, saves me lots of code.

function overloading is also very useful.

In terms of the current problem I have been shifting around different methods from running a constructor when I statically declare objects to assign parameters but then needing to have an init because I can't run code that plays with registers. Well this is the bit that I am not sure about that seems to have been much discussed here. So for the moment it makes sense to have static declarations of objects outside of main without calling a constructor and then run an init function once I know the hardware required for that object is setup. I'm still in the land of, everything that happens before main is a black box (OK I did delve into the startup file and set the register bit to turn the FPU on) and whatever I put outside of main is essentially static allocation of variables and then main runs.

It's this bit before main that is live running execution that I am missing an understanding of at the moment.
 

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 18835
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: non static C++ class objects with interrupt routines
« Reply #35 on: June 08, 2026, 08:02:16 am »
I am also not running any C++ library, I've not dared get into that yet.
 

Offline Jeroen3

  • Super Contributor
  • ***
  • Posts: 4495
  • Country: nl
  • Embedded Engineer
    • jeroen3.nl
Re: non static C++ class objects with interrupt routines
« Reply #36 on: June 08, 2026, 08:13:15 am »
I don't understand the obsession with static before main then.
If you only instantiate in main, it will be functionally the same, but no constructor will be called before main eliminating all the issues you experience.

You may even add static factory methods. Or even full factory pattern to help removing the instantiating complexity from main.

And if you want to share stuff, just make a DeviceContext singleton :)
« Last Edit: June 08, 2026, 08:14:51 am by Jeroen3 »
 

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 18835
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: non static C++ class objects with interrupt routines
« Reply #37 on: June 08, 2026, 09:02:06 am »
Well defining the object before main makes it accessible in a debugger even if the program runs to the dummy handler. I originally wanted to not have to write everything twice, first define, then run constructor but seems to be the best way all round. Once I have well debugged code I could move to instantiating as static in main and simply set up a pointer to interrupt methods to be used in the interrupt handler functions.
 

Offline paulca

  • Super Contributor
  • ***
  • Posts: 6004
  • Country: gb
Re: non static C++ class objects with interrupt routines
« Reply #38 on: June 08, 2026, 10:13:49 am »
Simon.  C++ is meant for a different animal.

In the world and doctrine that created it, the code in this thread lies outside the "System" boundary (you can look that up).

To get into C++ properly, you need to go well beyond this "glue code" to get where you seek.

C++ will wish you "OOP Model" your problem domain.  It will require isolation boundaries ... you found the first.  "System boundary".

Inside the System boundary, all code nouns and verbs are "Problem domain specific".  You don't have an "Array", you have a "CustomerCollection".  For a strawman example.

Now...  how often is that used and how often is that abused in modern C++.  Thats a valid question.  More.... how often is it used when it was NOT appropriate.

I watched the summary of an interview with the creator of C++ (now an old man), the question was, "Should I learn all of C++ and if so how?".  His answer was "Don't.  Forget all of the old Unix C stuff that is in there.  Embrace the latest version.".  That means "streams" for one example.  Rather than memcpy/strcpy et. al. stdlib.

So that is the world you seek to enter.

Just so you know.

Here is a preview:
AI Generated example.
Code: [Select]
error: 'has_serialize' is not a member of 'detail::traits_impl<MyClass, void>'
note: declaration of 'class detail::traits_impl<MyClass, void>'
note: friend declaration 'template<class T> class detail::traits_impl' does not name a type
error: 'class MyClass' has no member named 'serialize'
note: no matching function for call to 'detail::traits_impl<MyClass, void>::has_serialize'
Along with 100 others all in the same compiler output.
« Last Edit: June 08, 2026, 10:19:01 am by paulca »
"What could possibly go wrong?"
Current Open Projects:  STM32F411RE+ESP32+TFT for home IoT (NoT) projects.  Child's advent xmas countdown toy.  Digital audio routing board.
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 8299
  • Country: fi
    • My home page and email address
Re: non static C++ class objects with interrupt routines
« Reply #39 on: June 08, 2026, 10:29:47 am »
I am also not running any C++ library, I've not dared get into that yet.
You don't need to, either; all you really need is a runtime startup that copies initialized data, and executes constructors.

Whenever you statically instantiate a class using an empty initializer body, you have initialized data that gets "set up" whenever you copy initialized data from Flash to RAM.

Whenever you statically instantiate a class using a non-empty initializer body, the compiler constructs a special no-parameter no-return dynamically-named function to execute the initializer body in the code section (typically .text).  I am not exactly sure about the language spec details between different C++ versions and implementations, but my suggestion is to assume that it may put compile-time constants (including references to other objects) as initialized data, or initialize them in the initializer function code.  The address of this dynamically named function is then added to the .init_array section, which is simply a list of such pointers.  For destructors, similarly for .fini_array section.

In C (or extern "C" scope in C++), you can use __attribute__((constructor)) static void functionname(void) { ... } to add a locally-visible function to the .init_array section pointer array in file scope order, or __attribute__((constructor (priority))) static void functionname(void) { ... } in priority order, with 101 run first, 65534 just before those in file scope order, and 65535 in file scope order.  Similarly for destructor and .fini_array (with inverted priority order, so that normally both constructors and destructors use the same priority).  See GCC documentation for details.

In C++, you can use __attribute__((init_priority (priority))) Classname instancename; or __attribute__((init_priority (priority))) Classname instancename = Classname(...); to control the order of initializer functions; again 101 first, 65534 just before those in file scope order, and 65535 in file scope order.  See GCC documentation for details.

Note that underneath, both constructor and init_priority attributes use the exact same toolchain machinery.

With GCC/Clang/binutils toolchains on most ELF targets, the C runtime includes code to execute each pointer in the .init_array as a function call before calling main(), after copying initialized data from Flash/ROM to RAM.  This is why minimal freestanding C++ support does not require a C++ library, only a C++-compatible C runtime.

In reply #27 above, the Closure example shows how you can create and use an array of pointer pairs (one a void (*fun)(void *obj) function pointer, and the other a void *obj object reference) to construct an array across a number of source files, and execute them at a desired point in your main().  On 32-bit ARM, each closure is just 8 bytes, and can reside in Flash, so it is quite an effective method.

The main benefit of using a dedicated section (or sections) to collect entries across multiple source files is very useful for compile-time/link-time modularity.  For example, if you look at my RPN calculator example, the DEFINE_OP() macro defines a stack-based operation by name, description, and function pointer, into a dedicated "ops" section.  In main(), the do_op() function traverses the array to find the operator name in the ops section, and applies it if found.  This means that modifying or adding new operators requires only recompiling that operator source file, and relinking the binary.  The downside is that the array entry order is not easily controlled across source files.  To sort them, I usually create a script that dumps the section in the linked object, and generates C source code reproducing the section contents in desired order.  That way, sorting the section array contents is a post-link operation, running the script, compiling the generated C source code into an ELF object file, and replacing the array section in the linked file with the one from the ELF object file.  ELF object files can be directly modified, of course; it's just that each target architecture has its own relocation types, so both the array section and any relocations targeting it have to be modified.  I've found that regenerating the array contents in C and compiling that is much more robust, even if it involves parsing objdump output.
 

Offline paulca

  • Super Contributor
  • ***
  • Posts: 6004
  • Country: gb
Re: non static C++ class objects with interrupt routines
« Reply #40 on: June 08, 2026, 10:45:25 am »
Having been negative about C++, I am still curious as to the objective for Simon the OP.

Crossing other threads by yourself, Simon, you seem to be trying to expand your software knowledge outward, possibly from an MCU starting point.

The threads have pulled in two ways.  "Do not follow the 'standard' or academic direction and do not listen to the enterprise people" and "But the answers you seek are contained within that scope, the software industry has fixed these problems long ago"

It sounds like one of them needs to be correct.  However, I would argue that you have picked some pretty difficult middle grounds to learn in.

The boundary between MCU/Firmware/Hardware and "higher abstraction" world of general purpose computing is not a "stream you hop on over", it's an ocean separating two continents and they will never agree.  I learnt basic Z80 asm, aged 10.  Around 42 I learnt micro-controller coding.  I still struggle to find the common ground between these and the day job.

So my advice?  Unless you specifically 'need' to learn "MCU related C++ dev" for your CV, I would start learning C++ on a general purpose OS with an IDE and 8Gb of RAM.  Not 8k.  Learn C++ in it's natural habitat with it's natural work loads.  Then go back down towards the hardware and if you don't start asking, "Is C++ the right tool for this job?", I would be surprised.

For your current project.  Write the hardware interface in C.  Forget C++ completely.  Write that part in plan old C.  The C++ compiler will barely complain.  Then, when you want to model something more complex or abstract, "glue into" the C++ at specific interface points.  Then go full on C++ from there.  As mentioned in other threads a good example could be an OOP button model.  I would avoid things that require memory manipulation, string processing and even the STL collections framework until you can't anymore.
"What could possibly go wrong?"
Current Open Projects:  STM32F411RE+ESP32+TFT for home IoT (NoT) projects.  Child's advent xmas countdown toy.  Digital audio routing board.
 

Offline Jeroen3

  • Super Contributor
  • ***
  • Posts: 4495
  • Country: nl
  • Embedded Engineer
    • jeroen3.nl
Re: non static C++ class objects with interrupt routines
« Reply #41 on: June 08, 2026, 11:46:07 am »
Well defining the object before main makes it accessible in a debugger even if the program runs to the dummy handler.
But interrupts going into C++ should enter static methods, those are of no instance and should work regardless.

I originally wanted to not have to write everything twice, first define, then run constructor but seems to be the best way all round. Once I have well debugged code I could move to instantiating as static in main and simply set up a pointer to interrupt methods to be used in the interrupt handler functions.
The constructor should not perform work, only construct. It should only look inwards, like clearing memory, pre-setting state variables.
So, yes, you will need a "new Class" and "Class.Start()".
It's difficult to handle errors in constructors because they have no return value. You can only throw exceptions.
Especially for statics where you don't even see when and in what order the constructor is called.
 
The following users thanked this post: Alien Brother

Offline m k

  • Super Contributor
  • ***
  • Posts: 3407
  • Country: fi
Re: non static C++ class objects with interrupt routines
« Reply #42 on: June 08, 2026, 01:45:37 pm »
It's this bit before main that is live running execution that I am missing an understanding of at the moment.

"Main" is an artificial name, it could be what ever, it's not a beginning of anything else than what you or your tool desides.

There's a reset address, it's a starting point.
There can be what ever after that and before some main point.

Below is how old C++Builder starts a GUI(vcl) program, normally you don't touch that file, Unit1 is your place.

An exception is meaningful only when its handler is active.

Code: [Select]
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop
#include <tchar.h>
//---------------------------------------------------------------------------
USEFORM("Unit1.cpp", Form1);
//---------------------------------------------------------------------------
int WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
{
  try
  {
     Application->Initialize();
     Application->MainFormOnTaskBar = true;
     Application->CreateForm(__classid(TForm1), &Form1);
     Application->Run();
  }
  catch (Exception &exception)
  {
     Application->ShowException(&exception);
  }
  catch (...)
  {
     try
     {
       throw Exception("");
     }
     catch (Exception &exception)
     {
       Application->ShowException(&exception);
     }
  }
  return 0;
}
//---------------------------------------------------------------------------
Advance-Aneng-Appa-AVO-Beckman-Danbridge-Data Precision-Data Tech-Fluke-General Radio-H. W. Sullivan-Heathkit-HP-Kaise-Kyoritsu-Leeds & Northrup-Mastech-OR-X-REO-Schneider-Simpson-Sinclair-Tektronix-Tokyo Rikosha-Topward-Triplett-Tritron-YFE
(plus work shop of the world unknowns)
 

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 18835
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: non static C++ class objects with interrupt routines
« Reply #43 on: June 08, 2026, 03:09:16 pm »
Having been negative about C++, I am still curious as to the objective for Simon the OP.

Crossing other threads by yourself, Simon, you seem to be trying to expand your software knowledge outward, possibly from an MCU starting point.

The threads have pulled in two ways.  "Do not follow the 'standard' or academic direction and do not listen to the enterprise people" and "But the answers you seek are contained within that scope, the software industry has fixed these problems long ago"

It sounds like one of them needs to be correct.  However, I would argue that you have picked some pretty difficult middle grounds to learn in.

The boundary between MCU/Firmware/Hardware and "higher abstraction" world of general purpose computing is not a "stream you hop on over", it's an ocean separating two continents and they will never agree.  I learnt basic Z80 asm, aged 10.  Around 42 I learnt micro-controller coding.  I still struggle to find the common ground between these and the day job.

So my advice?  Unless you specifically 'need' to learn "MCU related C++ dev" for your CV, I would start learning C++ on a general purpose OS with an IDE and 8Gb of RAM.  Not 8k.  Learn C++ in it's natural habitat with it's natural work loads.  Then go back down towards the hardware and if you don't start asking, "Is C++ the right tool for this job?", I would be surprised.

For your current project.  Write the hardware interface in C.  Forget C++ completely.  Write that part in plan old C.  The C++ compiler will barely complain.  Then, when you want to model something more complex or abstract, "glue into" the C++ at specific interface points.  Then go full on C++ from there.  As mentioned in other threads a good example could be an OOP button model.  I would avoid things that require memory manipulation, string processing and even the STL collections framework until you can't anymore.

I started using C++ as a better, more robust and organized C. I find classes make it much easier to organize code. The stricter handling of variable types helps to prevent a lot of issues and the fact that the compiler respects and enforces type I create makes it easier to write code that simply won't compile if it is misused.

But apart from that I know nothing else of C++. Yes I do want to find the time to get into some C++ programming on Linux as I really don't want to slip into the python trap.

I don't know what I need to setup for C++ compared to C in terms of micro-controllers. I got myself up and running on VSC with just the compiler and make as I got fed up with the obfuscation of vendor IDE's and being tied to their debuggers.

So right now I can run programs written in C++ or at least compiled with the C++ compiler, my style is still probably very much C, but my programs only run if they are compiled with no optimization:

-W -Wall --std=gnu++17 -O0 -g -g3

As soon as I use "-W -Wall --std=gnu++17 -O1 -g -g3" I don't even make it into main.
 

Offline Alien Brother

  • Regular Contributor
  • *
  • Posts: 54
  • Country: fr
Re: non static C++ class objects with interrupt routines
« Reply #44 on: June 08, 2026, 05:17:27 pm »
What I'd personally do is start with a working C project, declare interrupt handlers and stuff called from startup code as `extern "C"`, and then try to get everything built with a C++ compiler. Not being able to get to main() is annoying debug, and the less code there is, the better.

So, yes, you will need a "new Class" and "Class.Start()".
I also think a separate start() method is the way to go, especially since the order in which peripherals are started may matter.
Then if you have a start() method, it's possible that the effect of the constructor can be computed at compile time, the constructor can be declared as constexpr, the global instance(s) of the class can be declared as constinit (in C++20), and we get rid of any constructor calls at runtime, just as if were in C, so no new() is needed.
« Last Edit: June 08, 2026, 05:19:18 pm by Alien Brother »
 

Offline Jeroen3

  • Super Contributor
  • ***
  • Posts: 4495
  • Country: nl
  • Embedded Engineer
    • jeroen3.nl
Re: non static C++ class objects with interrupt routines
« Reply #45 on: June 09, 2026, 05:43:52 am »
So right now I can run programs written in C++ or at least compiled with the C++ compiler, my style is still probably very much C, but my programs only run if they are compiled with no optimization:
That is probably unrelated to issues about the ++ but more issues about the incorrect use of the right keywords and attributes during for the low level stuff, like volatile and alignment.

C++ is very powerful, but if you go in blind without any software design or object orientated pattern knowledge you'll trip over yourself immediately.
Go buy this book, https://refactoring.guru/design-patterns, i think i recommended it before.
 

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 18835
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: non static C++ class objects with interrupt routines
« Reply #46 on: June 09, 2026, 06:46:56 am »
which one? refactoring or patterns?
 

Online gf

  • Super Contributor
  • ***
  • Posts: 1799
  • Country: de
Re: non static C++ class objects with interrupt routines
« Reply #47 on: June 09, 2026, 09:31:14 am »
"Optimization problems" mostly stem from a divergence between programmer assumptions and official C/C++ standard semantics. To avoid them, developers must know and understand exactly what the standard guarantees—and what it treats as undefined behavior. And yes, the detailed semantics of the abstract C or C++ machine are not as trivial as one may think. There are many potential pitfalls.
 

Offline paulca

  • Super Contributor
  • ***
  • Posts: 6004
  • Country: gb
Re: non static C++ class objects with interrupt routines
« Reply #48 on: June 09, 2026, 09:49:26 am »
"Optimization problems" mostly stem from a divergence between programmer assumptions and official C/C++ standard semantics. To avoid them, developers must know and understand exactly what the standard guarantees—and what it treats as undefined behavior. And yes, the detailed semantics of the abstract C or C++ machine are not as trivial as one may think. There are many potential pitfalls.

Indeed and sometimes the optimiser doesn't even throw errors.  It just warns and removes code which would lead to "undefined behaviour".  Depends on architecture etc. etc.

An example is the default optimiser on some architectures removing "null pointer" access as an "optimisation".  I was trying to write a "bootloader on 68k" it took quite a while to work out the optimiser had just deleted the funcitonal code writing to address 0x0.

In C++ "type transparency" and "type honesty", especially in the interface between C++ and C and direct memory manipulation are required for many optimisations and if the optimiser cannot "trust" your types it will through other warnings.  Things like casting an object or struct to a (char*) through a lower level and casting it back again somewhere else.  The optimiser will get annoyed.   Frame alignment warnings etc.
« Last Edit: June 09, 2026, 09:51:36 am by paulca »
"What could possibly go wrong?"
Current Open Projects:  STM32F411RE+ESP32+TFT for home IoT (NoT) projects.  Child's advent xmas countdown toy.  Digital audio routing board.
 

Offline Jeroen3

  • Super Contributor
  • ***
  • Posts: 4495
  • Country: nl
  • Embedded Engineer
    • jeroen3.nl
Re: non static C++ class objects with interrupt routines
« Reply #49 on: June 09, 2026, 10:30:25 am »
which one? refactoring or patterns?
Design Patterns of course.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf