Почему возникают проблемы с компоновщиком при передаче массива в стиле c методу, ожидающему std :: string? - PullRequest
1 голос
/ 01 апреля 2011

У меня есть класс Logger, который ожидает std :: string следующим образом:

class Logger
{
public:
    void Log(const std::string message);
};

А другой класс называет его так:

class MyClass
{
public:
    void MyMethod()
    {
        Logger logger;
        logger.Log("Hello World!"); // This line is causing linker error.

        // std::string myString("Hello World!");   If this and the line below are
        // logger.Log(myString);                   uncommented, I get no errors.
    }
};

Сообщение об ошибке:

Logger.cpp: undefined reference to `Logger::Log(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)`

Очевидно, что компоновщик знает о методе Log, потому что, как я показал выше, закомментированные строки позволят ему правильно ссылаться.

У кого-нибудь есть идея, что происходит? Дайте мне знать, если потребуется дополнительная информация.

Это использует gcc 4.4.3 под Linux (используя Eclipse)

EDIT:

Насколько я понимаю, вы всегда можете передать строки в стиле c методу, ожидающему std :: string, потому что std :: string имеет соответствующий конструктор копирования для его обработки.

EDITx2:

Момент лицевой стороны лица. Я нашел ошибку. Спасибо всем, кто заставил меня более внимательно взглянуть на мой код. Смотрите полное решение ниже.

Этот кусок кода должен был быть добавлен здесь в вопросе:

// cpp file

// This should have been in the header, not the cpp file.
inline void Logger::Log(const std::string message)
{
  /* do sutff */
}

Ответы [ 5 ]

1 голос
/ 01 апреля 2011

Похоже, либо вы забыли создать функцию Logger::Log, либо есть перегрузка для char*, которую вы нам не показываете, либо вы не связали Logger.o в случае сбоя.

1 голос
/ 01 апреля 2011

Хорошо, извините, я чувствую себя дураком.

class Logger
{
public:
    void Log(const std::string message);
}

Метод Log был расположен в его файле cpp как:

inline void Log(const std::string message) { /* stuff */ }

Поскольку он был объявлен встроенным в файл cpp, компоновщик не нашел его. Спасибо всем за то, что постоянно заставляете меня более внимательно смотреть на подпись.

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

1 голос
/ 01 апреля 2011

Ваша проблема в том, что вы не определили метод Log (он же Logger::Log). Вы объявили это, но нигде не определили.

Другая небольшая проблема заключается в том, что вы действительно должны объявить это так:

void Log(const ::std::string &message);

Нет особой причины заставлять абонентов делать копию строки, которую они вам передают.

Есть несколько возможностей, которые могут объяснить, почему вы думаете, что оно определено, даже если это не так.

Во-первых, вы не можете ссылаться в соответствующем файле .o, соответствующем файлу .cpp, где определена функция. Это означает, что вы определили его, но компоновщик не знает о вашем определении.

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

Другая возможность состоит в том, что вы определили функцию как встроенную. Если функция определена как встроенная, возможно, компилятор не выпустил код для нее. Многие компиляторы выдают код для встроенной функции только в том случае, если определение доступно в тот момент, когда на него ссылаются, а для справки требуется, чтобы функция имела действительный код где-то (например, получая ее адрес).

Если у вас есть функция, в которой определение встроено, эта функция обычно должна находиться в заголовочном файле, в противном случае ключевое слово inline бесполезно и может даже вызвать проблемы, поскольку весь остальной код будет предполагать фактический код, находящийся по определенному адресу, поддерживающему ваше объявление функции, за исключением одного файла .cpp, в котором он появляется, который может не ссылаться на функцию таким образом, чтобы принудительно вызывать код.

0 голосов
/ 02 апреля 2011

На самом деле, объявление для вашей функции-члена должно быть

void Log (const std :: string & message);

Помните, что передача аргументов по значению означает, что они будут скопированы. Если вы регистрируете только немного, это не будет иметь значения, но если вы регистрируете события, которые происходят с высокой скоростью, выделение / копирование строк начнёт сказываться.

Это должно быть const, поскольку регистратор не должен изменять передаваемые сообщения и не дает компилятору жаловаться, когда вы передаете аргумент const char *.

0 голосов
/ 01 апреля 2011

Ваш пример кода прекрасно компилируется и связывается в VC ++ 2010 и gcc 4.1.2, пока я предоставляю определение метода Logger :: Log () с закомментированным разделом кода или без него.

Вы уверены, что определили метод Logger :: Log ()? Вы пытались продублировать проблему в самой маленькой программе? Если это работает в небольшом тестовом примере, то в вашем исходном коде есть что-то более тонкое, вызывающее проблему.

Другая (удаленная) возможность, так как вы упомянули, что когда вы раскомментируете две строки, с которыми он прекрасно связывается, это то, что по какой-то причине компоновщик оптимизирует метод Logger :: Log (const std :: string).

...