1

I've been using a pattern in a library I'm creating that uses passes a String name of an object to its base object's constructor. I've tried using std::string and c-style strings but keep getting weird memory errors with Valgrind.

class Base {
public:
    Base( std::string name ) : name(name) {}
    virtual ~Base() {}
    std::string getName() { return name; }
private:
    std::string name;
};

class Derived : public Base {
public:
    Derived() : Base("Derived") {}
};

int main() {
    Base* derived = new Derived;
    std::cout << derived->getName() << "\n";
    delete derived;
}

(This compiles and runs fine in Valgrind)

Is something like this safe? I'm using 'const char*' instead of 'std::string' right now, is that safe?

Is there a safer alternative, preferably without using virtuals?

Edit: Is there a way to do this with templates? I don't want to use RTTI since it has the name mangled and I want the name to be 'normal' for use with scripting/data persistance.

h4tch
  • 264
  • 1
  • 8
  • Your base class needs to have a virtual destructor (this is probably the cause of the errors you're seeing). Also, you should probably use `unique_ptr` or `shared_ptr` instead of raw pointers. – syam Jul 21 '13 at 23:17
  • Just checked, all the bases are virtual in my code. – h4tch Jul 21 '13 at 23:24
  • For string literal constants, do not use a smart pointer a la `std::unique_ptr< char const[] >( "hello" )` because the `char const *` points to static data storage, not the heap. And I don't see the question here, this code is safe and fine but apparently doesn't represent the problematic part. – Potatoswatter Jul 21 '13 at 23:29
  • Alright thanks, thats what I was asking. I've read posts about problems with static initialization of strings, and had bizarre errors when I switched CStrings to std::strings. Just wanted to make sure this was safe. – h4tch Jul 21 '13 at 23:31

1 Answers1

0

Everything you do here is fine.

Templates would get you nothing because you still need to store a runtime pointer in the base class for dynamic identification.

Smart pointers would get you nothing because the lifetime of the string is the entire program. If you aren't computing anything, char const * and initialization from a string literal are ideal. If you are computing the string, then you can use static std::string const wrapped in a getter function.

class Derived : public Base {
public:
    Derived() : Base(get_name()) {}
private:
    static std::string const & get_name() {
        static std::string const name = "Derived"; // or = compute_name();
        return name;
    }
};

This avoids the static initialization order fiasco. (The getter function receives an extra multithreading-safe guard from the compiler.) The lifetime of the string is the lifetime of the program. The Base may store a string const & or a char const *, it doesn't really matter. I would recommend char const * because the string reference could potentially be accidentally initialized with a temporary.

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
  • Buyer beware: Visual C++ does not implement thread-safe initialization of function-local statics. – Casey Jul 22 '13 at 00:09
  • @Casey Are you sure? It's not a complicated feature. – Potatoswatter Jul 22 '13 at 00:13
  • Very sure. [Here's a question about VS2010.](http://stackoverflow.com/questions/10585928/is-static-init-thread-safe-with-vc2010) I've personally researched VS2012. Apparently it's [planned for "post-2013 release"](https://udta1g.blu.livefilestore.com/y2pMXBJL7l2a5UOf_pXnLXghSUhPWK8w5skFyc50SVFcMjVwa1guQnM6R0NNLN1buBUNPGbLBejpYXXBXSbqshQKKWVfQxvJjk2jGRPPbL-UBu7gaao4RxifZgPXY5ksdei/image1.png?psid=1). – Casey Jul 22 '13 at 00:19
  • @Casey I'll be darned, there it is. That compiler must be very crufty inside if inserting some boilerplate around every `static` local initialization represents real programming effort. – Potatoswatter Jul 22 '13 at 11:33