вторник, 18 октября 2011 г.

undefined reference to `vtable for


КОД
class A {
public:
  A() {
    // ...
  };
  // имеет виртуальные функции
}

class B : public A {
public:
  B() : A() {
    // ...
  }
  // определяет все виртуальные функции класса А
}


но после успешной компиляции при linkage получаю:

filename.o:filename.cpp:(.text+0x8) undefined reference to `vtable for A`


Обычно это происходит, если какой-то виртуальный метод класса объявлен, но нигде не определён. g++ обычно помещает vtable только в тот объектный файл, где определяется первый виртуальный метод класса, не объявленный как inline


Либо определяем здесь же реализацию виртуальных функций, либо делаем их "чистыми", помечая спецификатором "чистоты" - "=0"


Материал отсюда

error: there are no arguments to '' that depend on a template parameter, so a declaration of '' must be available

Когда получаешь error: there are no arguments to 'XXX' that depend on a template parameter, so a declaration of 'XXX' must be available. Это значит в шаблонном классе была вызвана не шаблонная функция.
Решение - явно указать Класс::XXX или включить функцию в namespace
Подробнее(отсюда):



There are no arguments to 'X' that depend on a template parameter, so a declaration of 'X' must be available
Aside: I have a C++ prograof moderate complexity that I have to return to every 12-18 months to fix an obscure bug or add a modest festure.And every time, I spent one or two days just trying to get the thing build with the latest compiler, which picks up previously legal code and decides to whine about it, generating dozens of errors.
This is not the fault of the compiler. This is the fault of C++ for being so sloppy and complex. This is why C++ should just die and give watoJava.

The Error

Compiling a templated class that "worked previously" (under gcc3.3. as opposed to 4.x), an error was thrown on a previously acceptable andnon-templated member:
/Users/agapow/Desktop/mloc/ComboMill.h:188: error: there are no arguments to 'SetMemberShip'
that depend on a template parameter, so a declaration of 'SetMemberShip' must be available
Huh. A simplfied version of the class looks like this:
template  class ComboMill
{
 // ...
 
 void SetMembership (bool iIsMember)
 {
  for (int i = 0; i < mMembership.size(); i++)
  {
   mMembership[i] = iIsMember;
  }
 }
 
 void First ()
 {
  // error on next line
  SetMembership (false);
 }

 // ...
};
SetMembership is called by a numbeof other methods to toggle the state of set members. But that isn't the problem - the problem occurs where other methods go to call SetMembership.

Solution

It'a tough error to google for, but basically C++ is being stricter about how it identifies what you are calling. Where previously a symbol "X" would be implicitly taken to refer to a member or method "X" on the parent class, here C++ is insisting that you make it explicit. Thus it can easily be fixed by writing:
void First ()
 {
  // error on next line
  this->SetMembership (false);
 }

 // ...
};
Onof the criticisms made about Python is that you have to explicitly membeaccess qualify with "self". It seems C++ is also not longer immune form this.

воскресенье, 16 октября 2011 г.

Немного о malloc и выделение памяти

malloc в glibc-е давно-давно выделяет память через mmap, и соответственно - если не инициализировать эту память, она так-же, будет нерезидентна и вообще, не будет заниматься. malloc(1024*1024*1024*2) отрабатывает мигом, и никак не сказывается на том, сколько в системе свободно памяти, а вот после memset-а по этому региону - память реально выделяется.




читаем в частности malloc(3):
When using malloc() be careful to avoid the following idiom:
           if ((p = malloc(num * size)) == NULL)
                   err(1, "malloc");
     The multiplication may lead to an integer overflow.  To avoid this,
     calloc() is recommended. 
Про выделение памяти:

Стек — это более быстрая память, но у неё есть недостаток, он работает по принципу FILO (первый пришёл — последний ушёл), то есть данные, которые попали в него позже, освободятся раньше. Для кучи вы можете в любой момент попросить любое количество свободной памяти (оператор new) и когда она вам будет не больше нужна, вы её вернёте системе (оператор delete). Для стека это невозможно. Размещение в нём данных происходит автоматически. Например, при вызове функции, все её аргументы помещаются в стек и локальные переменные тоже. Когда функция отработала, это всё из стека удаляется.

Кстати, помимо стека и кучи есть ещё сегмент, в котором живут статические переменные.



Чуть подробнее:


Стек, это структура данных по принципу "последний вошел - первый вышел". Используется в процессорах в первую очередь для организации вызовов функций, которые как правило вложены друг в друга. Обычно это происходит так: при входе в функцию, в стек помещаются параметры и адрес возврата - адрес следующей за вызовом команды. Сама функция внутри себя еще расширяет стек под локальные переменные. При выходе из функции стек восстанавливается к виду, какой он был до входа в функцию. Именно поэтому локальные переменные и параметры функций нельзя использовать за пределами функции - их уже нет в стеке. Когда мы вышли из функции, из стека также извлекается адрес возврата, ранее туда помещенный, и выполнение продолжается с него, т.е. со следующей за вызовом функции команды. И теперь нам снова доступны параметры и переменные из этой внешней вызывающей функции. И так будет независимо от того, насколько глубоко в вызовы функций мы зашли. Если функция 1 вызвала функцию 2, которая в свою очередь вызвала функцию 3, то у нас внизу стека будут параметры и переменные ф-ции 1, чуть выше - ф-ции 2, а еще выше - ф-ции 3. Доступны на данном этапе нам только параметры ф-ции 3, но стоит из нее выйти, и у нас снова переменные и параметры ф-ции 2. В общем, у объектов на стеке время жизни ограничено временем существования данного фрагмента стека, а область видимости ограничена тем, является ли данная область стека сейчас самой "верхней".
А куча - это динамическая память. Ты выделяешь из нее фрагмент нужного размера, и можешь обращаться к ней из любой части программы, имея валидный указатель. Время жизни объектов на куче такое, какое потребуется, они не "умирают" при выходе за область видимости. В большинстве языков ты сам должен очистить выделенную под объект память, в других же это сделает уборщик мусора.

Цитата (rockbear @ 31.08.09, 17:37)
значит чтобы получить ее значение нужно извлечь еще те переменные, которые находятся перед ней?


Нет :D Указатель на вершину стека храниться в специальном регистре, а когда тебе нужно извлечь переменную не из вершины, то берется значение из регистра плюс нужное смещение. Но учти, что функция ничего не знает о состоянии стека глубже своих переменных и параметров, и соответственно, не может обращаться к параметрам и переменным функции, ее вызвавшей



И плюс разный срок хранения данных: в стеке пока выполняется данная процедура, а в куче пока выполняется данный процесс 

пятница, 14 октября 2011 г.

Абстрактные классы в с++

Абстрактный класс в объектно-ориентированном программировании — базовый класс, который не предполагает создания экземпляров. 


На языке программирования C++ абстрактный класс объявляется включением хотя бы одной чистой виртуальной функции, типа virtual _сигнатура_функции_ =0;, которая как и другие может быть заменена.
Пример
class foo {
public:
    virtual void* bar() = 0;
}

вторник, 4 октября 2011 г.

*** glibc detected *** double free or corruption (out): ***

*** glibc detected ***  double free or corruption (out): *** - выдает glibc. Она выполняет дополнительные внутренние проверки целостности, с целью предотвращения и скорейшего выявления разрушения данных. По умолчанию, в случае выявления ошибки, в стандартное устройство stderr выводится подобное сообщение (или, если stderr не открыто, регистрируется через syslog)


По умолчанию, вызвавшая эту ошибку программа уничтожается; однако это (а также формирование сообщений) можно контролировать с помощью переменной окружения MALLOC_CHECK_. Поддерживаются следующие параметры:
0 - выдавать сообщение об ошибке и не уничтожать программу
1 - Выдавать сообщение об ошибке, но не уничтожать программу
2 - Не выдавать сообщение об ошибке, но уничтожать программу
3 - Выдавать сообщение об ошибке и уничтожать программу

Замечание:
Если переменной MALLOC_CHECK_ явно присвоено значение, отличное от 0, glibc будет выполнять больше расширенных проверок, что может отрицательно сказаться на производительности. 



У меня это было, когда проверялся ничем не инициализированный char* и потом вызывался free() от него:
char* c;
...
if (c != NULL) free(c);


c может не быть NULL и тогда будет пытаться освобождаться не выделенная память, что и вызывает ошибку.

понедельник, 3 октября 2011 г.

Мутексы в С++

Я для этого использую pthread_mutex.
pthread_mutex_t mut;

Сначала его нужно инициализировать:
int ret = pthread_mutex_init(&mut,NULL);

Далее - использовать:
ret = pthread_mutex_lock(&mut);
//Какой-то код
ret = pthread_mutex_unlock(&mut);

В конце нужно уничтожить мутекс:
ret = pthread_mutex_destroy(&mut)

При успешном выполнии ret = 0, иначе - номеру ошибки.

Mysql и C++

Доступ обеспечиваеся с помощью переменной типа MYSQL*;
Для начала нужно ее инициализировать :
MYSQL* conn = mysql_init(NULL);
mysql_init выделяет или инициализирует объект MYSQL, подходящий для функции mysql_real_connect(). Если аргумент mysql представляет собой указатель NULL, то эта функция выделяет, инициализирует и возвращает новый объект. В противном случае инициализируется указанный объект и возвращается его адрес. Если функция mysql_init() выделяет новый объект, то он будет освобожден при вызове функции mysql_close(), чтобы закрыть данное соединение.


Далее необходимо открыть соединение(mysql_connect лучше не использовать):
mysql_real_connect(conn, "host", "user", "pass", "database", 0, NULL, 0);
Для успешного соединения возвращаемая величина та же, что и величина первого параметра.
Функция mysql_real_connect() пытается установить соединение с сервером баз данных MySQL, работающим на хосте host. До успешного завершения функции mysql_real_connect() нельзя выполнять никакие другие функции интерфейса, за исключением mysql_get_client_info().


Теперь можно обращаться к базе данных с помощью mysql_query:
mysql_query(conn, "SELECT * FROM foo");

Выполняет запрос SQL, указанный в аргументе query в виде строки с нулевыми окончаниями. Данный запрос должен состоять из одной команды SQL. Нельзя добавлять к этой команде в качестве завершающих элементов точку с запятой (`;') или \g.
Функция mysql_query() не может использоваться для запросов, содержащих двоичные данные; вместо этого необходимо использовать функциюmysql_real_query() (двоичные данные могут содержать символ `\0', который mysql_query() интерпретирует как окончание строки запроса).
Для проверки, вернул данный запрос результирующий набор или нет, можно использовать функцию mysql_field_count().


Для получения результата запроса(когда запрос вида SELECTSHOW,DESCRIBEEXPLAIN) используется MYSQL_RES *result = mysql_store_result(conn) или MYSQL_RES *result = mysql_use_result(conn).
Функция mysql_store_result() читает весь результат запроса данного клиента, выделяет структуру MYSQL_RES и помещает результат в эту структуру.

Функция mysql_use_result() инициализирует извлечение результирующего набора, но фактически не производит чтение в клиенте подобно тому, как это делает функция mysql_store_result(). Вместо этого каждая строка должна извлекаться индивидуально посредством вызова функции mysql_fetch_row(). При этом методе результат запроса читается непосредственно на сервере без промежуточного хранения его во временной таблице или локальном буфере, что быстрее и требует намного меньше памяти, чем использование функции mysql_store_result(). Клиент будет выделять память только для текущей строки и буфер связи может расти до величины max_allowed_packet байтов.
С другой стороны, функцию mysql_use_result() нельзя использовать, если выполняется много операций по обработке каждой строки на клиентской стороне, или если вывод делается на терминал, на котором пользователь может нажать ^S (остановить вывод).
Это будет ограничивать работу сервера и будет мешать другим потокам в обновлении таблиц, из которых выбираются данные.
При использовании mysql_use_result() необходимо выполнять mysql_fetch_row(), пока не возвратится величина NULL, в противном случае невыбранные строки данного запроса будут возвращены как часть результирующего набора для следующего запроса. Если вы забыли сделать это, то интерфейс C будет выдавать ошибку Commands out of sync; you can't run this command now!
Нельзя использовать функции mysql_data_seek()mysql_row_seek()mysql_row_tell()mysql_num_rows() или mysql_affected_rows() для обработки результата, возвращенного функцией mysql_use_result(), а также нельзя запускать другие запросы, пока функция mysql_use_result() не завершится (однако после выборки всех строк функция mysql_num_rows() будет корректно возвращать количество выбранных строк).



Потом - освободить ресурс:
mysql_free_result(result);
Освобождает память, выделенную для результирующего набора данных функциями mysql_store_result()mysql_use_result()mysql_list_dbs() и т.д. После выполнения операций с результирующим набором необходимо освободить используемую под него память вызовом функции mysql_free_result().


В конце надо закрыть соединение:
mysql_close(conn);
Закрывает ранее открытое соединение. Функция mysql_close() также освобождает дескриптор данного соединения, указанный в mysql, если данный дескриптор был выделен автоматически функциями mysql_init() или mysql_connect().


Взята куча данных с http://mysql.ru/docs/man/C_API_functions.html