0

I'm developing a class for my AVR cpu.

The class is going to handle all port related operations like Set, Read, etc; Constructor looks like:

(...)
public:
    Port(volatile uint8_t * DDR, volatile uint8_t * PORT);
(...)

And it is constructed at the beginning of the main():

int main()
{
    Port PortA(&DDRA, &PORTA);
    (...)
}

Now I want to make sure that nowhere else in the program object with same parameters would be constructed. It is sure that I cannot create array or map to find it out and throw an exception. It must be done at compile time. So basicly I want to force avr-g++ to check if any other Port(the same first parameter OR the same second parameter) exists in current project.

All functions uses pointers / references to Port objects.

peku33
  • 3,628
  • 3
  • 26
  • 44

4 Answers4

2

How about the following?

The address of the pointers has to be known at compile-time.

template<int *p>
class Tester
{
public:
    static Tester& GetInstance()
    {
        static Tester t;
        return t;
    }

private:
    Tester() {}
};

int i;

int main()
{
    Tester<&i>& t = Tester<&i>::GetInstance();
}
Neil Kirk
  • 21,327
  • 9
  • 53
  • 91
  • Care to elaborate for someone who isn't aware of the template concept? I mainly use C for embedded programming. – Rev Oct 16 '14 at 07:05
  • @Rev1.0 It's a fairly advanced used of templates so difficult to explain briefly. For each pointer address provided as the template parameter, a new class type is defined. By making the constructor private, you can control exactly how many of that class type for that pointer address are created. – Neil Kirk Oct 16 '14 at 09:18
  • Thank you, this gives me a pointer (no pun :P) in the right direction if I decide to read up on that. – Rev Oct 16 '14 at 09:23
0

If you only want one instance of a class, then why use classes? The whole purpose of classes, is that you can have multiple intances. Just stick to global variables and free functions.

  • Because there will be multiple instances of the Port class with different addresses for the DDR and main port ADDR. He's just trying to avoid the problems that **WILL** ensue if two different instances of the Port class attempt to reference the same hardware. – dgnuff Oct 16 '14 at 03:24
-1

This is not pretty, but it does get the job done. 10 years experience says embedded work tends to be like this at times. :/

I tested this with a simple class under MSVC, you'll have to adapt for your needs, but it does demonstrate the principle.

Declare your class like this in the header:

class t
{
public:
#ifdef ALLOW_CTOR
    t(int i);
    ~t();
#endif
    int get();

private:
    int m_i;
};

Then in exactly one file add the line:

#define ALLOW_CTOR 1

include the header file, declare your port instances as file scope variables, and then implement all the class methods of your class, ctor, dtor, accessors, etc.

If you do not place ALLOW_CTOR line in other source files, they can still use the accessor methods in your class, but they can't use the constructor. In the absence of the correct constructor, MSVC complains because it tries to use the default copy constructor, but since the parameter lists don't match, it fails. I suspect the compiler you're using will fail in some way, I'm just not sure exactly what the failure will be.

dgnuff
  • 3,195
  • 2
  • 18
  • 32
-1

@Neil Kirk

If failure to provide a declaration of a ctor at all for a compilation unit leads to undefined behavior, then there are ways to solve that.

class t
{
#ifdef ALLOW_CTOR
public:
#else
private:
#endif
    t(int i);

public:
    ~t();
    int get();

private:
    int m_i;
};

marks the ctor as public in one, but private in all other compilation units, leading to a well defined error: the inability to access a private member function.

dgnuff
  • 3,195
  • 2
  • 18
  • 32
  • It is not the presence or absence of a constructor that is the problem: it is the fact that you are introducing inconsistent definitions observed by multiple source files. That is UB. – underscore_d Jan 30 '17 at 12:21