2013-07-21 1 views
1

Я использую шаблон в библиотеке, которую я создаю, которая использует строковое имя объекта для своего конструктора базового объекта. Я попытался использовать строки std :: string и c-style, но продолжаю получать странные ошибки памяти с помощью 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; 
} 

(компилируется и работает нормально, в Valgrind)

Это что-то вроде этого безопасно? Я использую 'const char *' вместо 'std :: string' прямо сейчас, это безопасно?

Есть ли более безопасная альтернатива, желательно без использования виртуальных?

Редактировать: Есть ли способ сделать это с помощью шаблонов? Я не хочу использовать RTTI, так как он имеет имя искаженное, и я хочу, чтобы имя было «нормальным» для использования с поддержкой сценариев/данных.

+0

Ваш базовый класс должен иметь виртуальный деструктор (вероятно, это причина ошибок, которые вы видите). Кроме того, вы должны использовать 'unique_ptr' или' shared_ptr' вместо исходных указателей. – syam

+0

Только что проверено, все базы виртуальны в моем коде. – h4tch

+0

Для строковых литерал-констант не используйте умный указатель a la 'std :: unique_ptr (« hello »)', потому что 'char const *' указывает на статическое хранение данных, а не на кучу. И я не вижу здесь вопроса, этот код является безопасным и точным, но, по-видимому, не представляет собой проблемную часть. – Potatoswatter

ответ

0

Все, что вы здесь делаете, это прекрасно.

Шаблоны ничего не получат, потому что вам все равно нужно сохранить указатель времени выполнения в базовом классе для динамической идентификации.

Умные указатели ничего не получат, потому что время жизни строки - это вся программа. Если вы ничего не вычисляете, то char const * и инициализация из строкового литерала идеальны. Если вы вычисляете строку, вы можете использовать static std::string const, завернутый в функцию геттера.

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

Это позволяет избежать фиаско порядка статического инициализации. (Функция getter получает от компилятора дополнительную защиту от многопоточности.) Время жизни string - это время жизни программы. Base может хранить string const & или char const *, это не имеет значения. Я бы порекомендовал char const *, потому что ссылка string потенциально может быть случайно инициализирована временным.

+0

Опытный покупатель: Visual C++ не реализует потокобезопасную инициализацию функции-локальной статистики. – Casey

+0

@Casey Вы уверены? Это не сложная функция. – Potatoswatter

+0

Очень уверен. [Вот вопрос о VS2010.] (Http://stackoverflow.com/questions/10585928/is-static-init-thread-safe-with-vc2010) Я лично исследовал VS2012. Видимо, это [запланировано на "пост-2013 выпуска"] (https://udta1g.blu.livefilestore.com/y2pMXBJL7l2a5UOf_pXnLXghSUhPWK8w5skFyc50SVFcMjVwa1guQnM6R0NNLN1buBUNPGbLBejpYXXBXSbqshQKKWVfQxvJjk2jGRPPbL-UBu7gaao4RxifZgPXY5ksdei/image1.png?psid=1). – Casey