17

Is it possible to know the object instance name / variable name from within a class method? For example:

#include <iostream>

using namespace std;

class Foo {
     public:
          void Print();
};

void Foo::Print() {
     // what should be ????????? below ?
     // cout << "Instance name = " << ?????????;
}

int main() {
    Foo a, b;
    a.Print();
    b.Print();
    return 0;
}
Alex B
  • 82,554
  • 44
  • 203
  • 280
Adam Dempsey
  • 2,913
  • 5
  • 24
  • 26
  • curious if this is just for debugging/logging purposes ? i hope so – Simon_Weaver Nov 25 '09 at 19:28
  • Yea just wondered if it was possible to help narrow down a problem I was having. – Adam Dempsey Nov 25 '09 at 21:58
  • 1
    It's not clear what do you mean by instance name. Lets consider `Foo bar[200]`. What instance name should be for `bar[13]`? Or even prosaic, let `new Foo()` returned `0xbadbad` pointer. What is instance name for `*(0xbadbad)`? – ivaigult Aug 23 '15 at 21:32
  • Maybe that helps: http://llvm.org/docs/SourceLevelDebugging.html#c-c-global-variable-information In clang you can think of accessing some debug information - but please do not ask me further questions about this - I never use it and no plan to use it in future... – PiotrNycz Aug 24 '15 at 14:29
  • you could emit a nice form of this. ie the address of the object – pm100 Aug 25 '15 at 23:25

14 Answers14

29

No. Variable names are for the programmer, the compiler sees addresses.

Other languages that provide meta-data/reflection about their program might provide this functionality, C++ isn't one of those languages.

GManNickG
  • 494,350
  • 52
  • 494
  • 543
25

Not with the language itself, but you could code something like:

#include <iostream>
#include <string>

class Foo
{
 public:
    Foo(const std::string& name) { m_name = name;}
    void Print() { std::cout << "Instance name = " << m_name << std::endl; }

  private:
    std::string m_name;
};

int main() 
{
    Foo a("a");
    Foo b("b");

    a.Print();
    b.Print();

    return 0;
}
bltxd
  • 8,825
  • 5
  • 30
  • 44
Steven Keith
  • 1,789
  • 15
  • 23
16

Variable names do not exist in the compiled code.

However you can use some #define to get the name in preprocessing and let the names be populated before the compile.

Something like this:

#define SHOW(a) std::cout << #a << ": " << (a) << std::endl
// ...
int i = 2;
SHOW (i);
Dominic Rodger
  • 97,747
  • 36
  • 197
  • 212
Svetlozar Angelov
  • 21,214
  • 6
  • 62
  • 67
9

What would that mean?

void f(T const& p) {
    cout << p.name();
}

T r() {
    T c;
    return c;
}

void g() {
    T a;
    cout << a.name();
    T & b = a;
    cout << b.name();
    T * ptr = &b; 
    cout << ptr->name();

    T d = r();
    cout << d.name();
}

What would you expect? "a" each time? And what about c/d?

Luc Hermitte
  • 31,979
  • 7
  • 69
  • 83
8

Variable names don't survive compilation. The best you can do is to pass the variable name into the object constructor and store it inside the object by using a macro. The latter will lead to really ugly code so you would only want this as a last resort.

sharptooth
  • 167,383
  • 100
  • 513
  • 979
8

For the bounty: This is one of the biggest and most disgusting hacks I've ever created but its good enough for debug reasons in my opinion

#include <iostream>

#include <typeinfo>
#define DEBUG_INSTANCE( classtype, name ) class _ ## classtype ## _INSTANCE_ ## name ## _  : public classtype \
    { \
        public: \
            _ ## classtype ## _INSTANCE_ ## name ## _ (){ } \
    }; \
_ ## classtype ## _INSTANCE_ ## name ## _ name

class Foo {
public:
    virtual void _MakeTypeIDRunTime() { }
    // A virtual method in the class forces typeid(*this) to be used runtime rather than compiled
    // See: https://stackoverflow.com/a/6747130/1924602

    void Print();
};

void Foo::Print() {
    std::cout << "Instance name = " << typeid(*this).name() << std::endl;
}

int main()
{
    DEBUG_INSTANCE(Foo, a);
    DEBUG_INSTANCE(Foo, b);

    a.Print();
    b.Print();

    system("PAUSE");
    return 0;
}

Output:

Instance name = ?AV_Foo_INSTANCE_a_@?1?main@
Instance name = ?AV_Foo_INSTANCE_b_@?1?main@
Press any key to continue . . .

This macro will create a class that inherits Foo and name contains the instance name. Only limitation is that Foo has a default constructor and must contain a virtual method in order for typeid to accept inherited classes and be called used at runtime. See https://stackoverflow.com/a/6747130/1924602 for a better explanation

Might be possible to support constructors if you use the __VA_ARGS__ macro

Community
  • 1
  • 1
otc
  • 431
  • 4
  • 15
5

It is certainly possible for an instance to know its name from within the class method:

#include <iostream>

class Foo {
  public:
    void Print() { std::cout << "Instance name = " << this << std::endl; }
};

int main() {
    Foo a, b;
    a.Print();
    b.Print();
    return 0;
}

will produce the output similar to this:

Instance name = 0x7fff502b8b48
Instance name = 0x7fff502b8b40

As for knowing the variable name, it is certainly not possible. The existence of the object does not imply the existence of the variable - this instance:

new Foo();

will exist for the remaining duration of the process, yet will never be associated with any variable. The language concept of variables is not reflected in the contents of said variables, and any potential relation between language variable and an object is expressed only in the generated code and not in generated data or meta-data. Barring of course the access to the debug information which, as already pointed out, is not part of the language.

Leon
  • 89
  • 1
  • 2
  • I don't agree you can call `this` a name (given that it's the object address), but can pass as a `uniqe identifier`. Will award you the bounty if you add an example how to get the variable names from memory addresses from a debug built binary. Not at run time but as a separate step (by grepping the binary or something). Please, let the example include the compilation command with all required flags. – TheMeaningfulEngineer Aug 26 '15 at 07:18
  • Well, it is a matter of definition. As for the rest of your comment, both a, and b are auto variables, hence they would not exist in symbol tables in binary files. The only time to match address (`this` pointer) with the variable would be the runtime examination of the previous stack frame and matching its content to the debug info. Basically what debugger does, just from within the process. Not impossible, but it'd take highly specialised and unportable piece of code that would have little, if any, real life use. – Leon Aug 30 '15 at 16:09
1

It is not possible with the language itself. However, you can use preprocessor to get it. But it is not going to be clear and you will have to be careful if your classes have different constructors. Also you will have to do it in each class.

I reuse the example of Steven Keith in combination with #define preprocessor:

#include <iostream>
#include <string>

using namespace std;

class Foo
{
 public:
    Foo(const string& name) : m_name(name) {}
    void Print() { cout << "Instance name = " << m_name << endl; }

 private:
    string m_name;
};

#define DRESSED_Foo(var) Foo var(#var)

int main() 
{
    DRESSED_Foo(a);
    DRESSED_Foo(b);

    a.Print();
    b.Print();

    return 0;
}
blashser
  • 921
  • 6
  • 13
1

The keyword this

I'm new to programming, but having studied class structure I believe what you might be looking for is the keyword this. As in the example below (taken from cplusplus.com), you can see that this is used anywhere the class needs to refer to itself.

Therefore, it is possible for a constructor to do this as well.

// example on this
#include <iostream>
using namespace std;

class Dummy {
  public:
    bool isitme (Dummy& param);
};

bool Dummy::isitme (Dummy& param)
{
  if (&param == this) return true;
  else return false;
}

int main () {
  Dummy a;
  Dummy* b = &a;
  if ( b->isitme(a) )
    cout << "yes, &a is b\n";
  return 0;
}

http://www.cplusplus.com/doc/tutorial/templates/

ganrob
  • 39
  • 1
0

It is not possible. C++ does not have a concept of "reflection" like .NET platform. But MFC library has CRunTime class - you can see for example.

Captain Comic
  • 15,744
  • 43
  • 110
  • 148
0

Debug symbols do not exist as far as C++ is concerned. As a result, no C++ mechanism allows you to do anything with them. Would it be possible to create platform-specific solution which would work? Possible. One would have to analyze the image of the process in memory, parse it according to specific format, figure out debug symbols (and frames) and map them to addresses. Essentially, debug itself. Does it worth the trouble? Not in my opinion.

SergeyA
  • 61,605
  • 5
  • 78
  • 137
0
This is not possible "Directly", consider this simple program;

 // stove.cpp 

#include <string.h>
#include <stdio.h>
#include <iostream>

using namespace std;

class Foo {
   char* t;
   size_t length;

     public:
     Foo()
     {
       t = new char(8);
       t = static_cast<char*>(static_cast<void*>(this));

     }
      void Print();
};

    void Foo::Print() {
         // what should be ????????? below ?
          cout << this << " " << strlen (t) << t << endl;
    }

    int main() {
        Foo a;
        a.Print();
        Foo b;
        b.Print();
        return 0;
    }

    you can check the value of t in gdb for both a and b objects,
1) run binary in gdb and put breakpoints on lines where both objects a and b gets created.
2) for both objects a and b , after creation (or in print function, check
print this
print t
    18           }
    (gdb) print this
    $1 = (Foo * const) 0x7fffffffe6e0
    (gdb) print t
    $2 = 0x7fffffffe6e0 "\340\346\377\377\377\177"
    ...
    ...
    ...
    30          Foo b;
    (gdb) s
    Foo::Foo (this=0x7fffffffe6d0) at stov.cpp:15
    15             t = new char(8);
    (gdb) n
    16             t = static_cast<char*>(static_cast<void*>(this));
    (gdb) n
    18           }
    (gdb) print this
    $3 = (Foo * const) 0x7fffffffe6d0
    (gdb) print t
    $4 = 0x7fffffffe6d0 "\320\346\377\377\377\177"
Naumann
  • 357
  • 2
  • 13
  • Can you please format your answer a bit, this might just be what I was looking for. – TheMeaningfulEngineer Aug 27 '15 at 11:23
  • just formated, basically i think you get confused by print function and print command i used in gdb, so just debug it and use " p this" and "p t" .. – Naumann Aug 27 '15 at 12:43
  • I was aiming to format the answer visually and not have unnecessary comments in the code. After rechecking though I seem to have mistaken about this being the solution I was looking for. At no point in gdb is the actual variable name actually printed, and printing `this` to identify the variable can be done without debug symbols whatsoever. – TheMeaningfulEngineer Aug 27 '15 at 13:01
  • yes that is why i stated as "There is no solution" and in print function, i printed "this" and "t". – Naumann Aug 27 '15 at 13:53
0

You can do it using #define. Define a macro which would save variable name inside class:

#include <iostream>
#include <string>

using namespace std;

#define CREATE_FOO(f) Foo f = Foo(#f);

class Foo {
     public:
          void Print() const;
          Foo(string s): name(s) {};
     protected:
          string name;

};

void Foo::Print() const  {
     cout << "Instance name = " << name;
}


int main() {
    CREATE_FOO(a);
    CREATE_FOO(b);
    a.Print();
    b.Print();
    return 0;
}
EvgeniyZh
  • 898
  • 9
  • 21
0
class Food {
  private:
    uint8_t m_Temperature;  // cooking temperature

  public:
    //constructor
    Food (uint16_t Temperature) {
      m_Temperature = Temperature;
    }
    //forward declaration
    void CookIt(uint16_t NewTemperature);
    
};  // class

Food Burger(123);
Food Fries(233);

void Food::CookIt(uint16_t NewTemperature) {
  Serial.print("I am cooking ");
  if(this==&Burger) Serial.print("burger");
  if(this==&Fries)  Serial.print("fries");
  Serial.print(" at ");
  Serial.print(NewTemperature);
  Serial.println(" Deg C");
  Serial.println();

}
PeteDD
  • 1
  • 1
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Feb 16 '23 at 12:06