Использование STL в UDF на C++Builder

Запросы, планы, оптимизация запросов, ...

Модераторы: kdv, CyberMax

Ответить
Orso
Сообщения: 8
Зарегистрирован: 13 май 2009, 15:58

Использование STL в UDF на C++Builder

Сообщение Orso » 13 май 2009, 16:43

Доброго времени суток.
Нужно следующее:
1. У кого есть опыт использования STL в UDF-ках написанных на C++Builder'e поделитесь есть ли подводные камни при работе?
2. В UDF-ке создан класс (упрощенно):

Код: Выделить всё

#ifndef File1H
#define File1H

#include <vector>

#ifdef __DLL__
# define DLL_E __declspec(dllexport)
#endif

class MS
{
 private:
  vector<int> vInt;

 public:
  void FillVector(){for(int i = 0; i < 500; i++) vInt.push_back(i);};
  int   GetElement(int Pos){return vInt[Pos]};
} 
typedef MS *PMS; 

Далее есть экспортируемые функции

Код: Выделить всё

extern "C" PMS DLL_E __cdecl Create();
extern "C" int   DLL_E __cdecl Free(PMS);
extern "C" int   DLL_E __cdecl Fill(PMS);
extern "C" int   DLL_E __cdecl GetElement(PMS,const int *);

PMS __cdecl Create()
{
 return new MS();
}

int __cdecl Free(PMS DS)
{
 delete DS;
 return 0;
}

int __cdecl Fill(PMS DS)
{
 return DS->FillVector();
}

int __cdecl GetElement(PMS DS,int Pos)
{
 return DS->GetElement(Pos);
}

#endif
в Firebird базе данных декларю функции:

Код: Выделить всё

DECLARE EXTERNAL FUNCTION DSCREATE
RETURNS INTEGER BY VALUE
ENTRY_POINT 'Create' MODULE_NAME 'MSDLL';

DECLARE EXTERNAL FUNCTION DSFILL
    INTEGER
RETURNS INTEGER BY VALUE
ENTRY_POINT 'Fill' MODULE_NAME 'MSDLL';

DECLARE EXTERNAL FUNCTION DSGETELEMENT
    INTEGER,
    INTEGER
RETURNS INTEGER BY VALUE
ENTRY_POINT 'GetElement' MODULE_NAME 'MSDLL';

DECLARE EXTERNAL FUNCTION DSFREE
    INTEGER
RETURNS INTEGER BY VALUE
ENTRY_POINT 'Free' MODULE_NAME 'MSDLL';
В итоге мне нужно получить в хранимую процедуру на сервере указатель на объект класса MS при помощи функции Create()
и затем при помощи данного указателя работать с объектом.
Однако, получается нечто неясное. Через указатель, возвращенный функцией Create() можно вызывать методы созданного объекта, но только не те, что модифицируют поля объекта. Т.е. если у объекта есть метод, например, что-то записывающий в лог-файл - все ок, метод срабатывает данные в лог пишутся. Но если пытаешься вызвать метод FillVector, который заполняет вектор данными - валится с Exception'ом...
Причем если добавить к вышеописанному классу конструктор и работать с вектором в конструкторе (например добавить в него что-то) - все ок. Но затем при работе с объектом через указатель из хранимой процедуры, получить данные из вектора (записанные в конструкторе) опять же нельзя.

Подскажите пожалуйста как правильно организовать работу с объектом класса, через указатель, полученный в хранимой процедуре посредством UDF.
Или, если я неправ в чем то изначально, направьте на путь истинный.
Заранее большое спасибо.

Orso
Сообщения: 8
Зарегистрирован: 13 май 2009, 15:58

Re: Использование STL в UDF на C++Builder

Сообщение Orso » 13 май 2009, 16:50

Да, прошу прощения.
Сервер: Firebird 2.0.4
RAD: Borland C++Builder 6

hvlad
Разработчик Firebird
Сообщения: 1244
Зарегистрирован: 21 мар 2005, 10:48

Re: Использование STL в UDF на C++Builder

Сообщение hvlad » 13 май 2009, 16:53

Отлаживать DLL умеешь ? Вперёд ;)

Orso
Сообщения: 8
Зарегистрирован: 13 май 2009, 15:58

Re: Использование STL в UDF на C++Builder

Сообщение Orso » 13 май 2009, 17:05

Если нарисовать клиента для этой DLL на C++Builder и объявить функции не __cdecl а __stdcall то все работает...
с __cdecl выдает те же ошибки. Так понимаю где-то проблема с правильностью передачи параметров...

hvlad
Разработчик Firebird
Сообщения: 1244
Зарегистрирован: 21 мар 2005, 10:48

Re: Использование STL в UDF на C++Builder

Сообщение hvlad » 13 май 2009, 17:09

а) зачем с extern "C" ещё и __cdecl ?
б) отладчиком смотри, где именно и какое исключение

Orso
Сообщения: 8
Зарегистрирован: 13 май 2009, 15:58

Re: Использование STL в UDF на C++Builder

Сообщение Orso » 13 май 2009, 17:17

Исключение возникает в:

Код: Выделить всё

void FillVector(){for(int i = 0; i < 500; i++) vInt.push_back(i);// вот тут оно (исключение, которое говорит, что вектора по сути не существует) и возникает. Причем если приделать логирование, и в начале этой процедуры до цикла вывести в лог vInt.size() то будет шестизначное отрицательное значение. Даже если вектор до этого заполнить данными, например, в конструкторе...};

hvlad
Разработчик Firebird
Сообщения: 1244
Зарегистрирован: 21 мар 2005, 10:48

Re: Использование STL в UDF на C++Builder

Сообщение hvlad » 13 май 2009, 17:47

Сравни указатель, который возвращает Create, с тем, который передаётся в Fill

PS Детсад... практические навыки работы есть вообще ?

Tonal
Сообщения: 104
Зарегистрирован: 30 сен 2007, 13:42

Re: Использование STL в UDF на C++Builder

Сообщение Tonal » 14 май 2009, 07:39

hvlad писал(а):а) зачем с extern "C" ещё и __cdecl ?
Вообще-то extern "C" влияет только на манглинг имён, а не на соглашение о вызове.
Ежели его не ставить, будет дефолтное. :)

hvlad
Разработчик Firebird
Сообщения: 1244
Зарегистрирован: 21 мар 2005, 10:48

Re: Использование STL в UDF на C++Builder

Сообщение hvlad » 14 май 2009, 16:03

Tonal писал(а):
hvlad писал(а):а) зачем с extern "C" ещё и __cdecl ?
Вообще-то extern "C" влияет только на манглинг имён, а не на соглашение о вызове.
Ежели его не ставить, будет дефолтное. :)
Угу, а по дефолту конечно же fastcall :-D

В данном случае это не важно по сути, но показывает невеликий опыт автора, имхо.

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1436
Зарегистрирован: 15 сен 2005, 09:05

Re: Использование STL в UDF на C++Builder

Сообщение Dimitry Sibiryakov » 14 май 2009, 18:21

Поскольку ЕМНИП параметры в UDF передаются по ссылке, то остальные функции при таком объялении получают совсем не то, что вернула Create(). Аффтар, ты либо убери у Create BY VALUE, либо добавь к параметрам остальных ещё по звёздочке.

Orso
Сообщения: 8
Зарегистрирован: 13 май 2009, 15:58

Re: Использование STL в UDF на C++Builder

Сообщение Orso » 15 май 2009, 10:07

Доброго времени суток...
Для hvlad
PS Детсад... практические навыки работы есть вообще ?
То-то я смотрю Вы мне еще ничего умного не сказали... Видимо сказывается БОГАТЫЙ практический опыт...
Спасибо...

Orso
Сообщения: 8
Зарегистрирован: 13 май 2009, 15:58

Re: Использование STL в UDF на C++Builder

Сообщение Orso » 15 май 2009, 10:12

И что-то я не пойму в данном форуме только Гуру, и неопытным сюда вход заказан? Если Вы настолько опытны и подкованы - помогите практическим советом. Критиковать и громко кричать на этом форуме, я смотрю могут, а вот сказать что-то полезное...

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Re: Использование STL в UDF на C++Builder

Сообщение WildSery » 15 май 2009, 11:44

Тебе про дебагер уже два раза намекнули.

Точно, детсад. Ещё и буйный. Где-то Дима ходит...

Orso
Сообщения: 8
Зарегистрирован: 13 май 2009, 15:58

Re: Использование STL в UDF на C++Builder

Сообщение Orso » 15 май 2009, 12:03

Сообщение hvlad » 13 май 2009, 16:47
Сравни указатель, который возвращает Create, с тем, который передаётся в Fill

PS Детсад... практические навыки работы есть вообще ?
Совпадают. К тому же изначально я написал, что через указатель, который возвращен в хранимку методом Create(), можно вызывать те методы объекта, которые не работают с полями объекта, к примеру с методом, который пишет логирование в файл... Когда же вызываешь метод, работающий с полями, возникает исключение, которое говорит, что идет обращение по неверному адресу памяти...

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1436
Зарегистрирован: 15 сен 2005, 09:05

Re: Использование STL в UDF на C++Builder

Сообщение Dimitry Sibiryakov » 15 май 2009, 13:07

Orso писал(а):Совпадают.
Врёшь. Либо сейчас либо в первом посте, поскольку при таких объявлениях они совпадать не могут. Create возвращает адрес в виде целого, но в Fill передаётся не само это целое, а его адрес, т.е. ссылка на ссылку на объект в то время как она ожидает непосредственно ссылку на объект. Отсюда обращение к неверному адресу, поскольку она вместо this использует брюхо FBшного DSC, которое далеко не MS со всеми вытекающими.

PS: Кстати, я был не прав - удаление BY VALUE только ухудшит ситуацию.

Orso
Сообщения: 8
Зарегистрирован: 13 май 2009, 15:58

Re: Использование STL в UDF на C++Builder

Сообщение Orso » 15 май 2009, 14:07

Врёшь. Либо сейчас либо в первом посте, поскольку при таких объявлениях они совпадать не могут...
Простите, в таком случае как Вы считаете метод, не работающий с полями объекта должен выполняться?
Если не должен, то врете именно Вы. Ибо он работает...
К примеру вот такой метод

Код: Выделить всё

...  
int LogMessage(char *Mess){
                             DWORD write = 0;

                             HANDLE hFile = CreateFile("D:\\LogFile.log",
                             GENERIC_READ|GENERIC_WRITE,
                             FILE_SHARE_READ|FILE_SHARE_WRITE,
                             NULL,
                             OPEN_ALWAYS,
                             FILE_ATTRIBUTE_NORMAL,
                             NULL
                            );

                            if(hFile != INVALID_HANDLE_VALUE)
                            {
                             SetFilePointer(hFile,0,0,FILE_END);

                              WriteFile(
                                        hFile,
                                        Mess,
                                        strlen(Mess),
                                        &write,
                                        NULL
                                       );
                            }

                            CloseHandle(hFile);
                           };
...
и такая функция

Код: Выделить всё

//---------------------------------------------------------------------------
int __cdecl DsLogMessage(PMS DS)
{
 return DS->LogMessage("Тестовое сообщение в лог...");
}
//---------------------------------------------------------------------------
вызванная из хранимки через указатель полученный функцией Create

Код: Выделить всё

CREATE PROCEDURE UDF_TEST 
As
Declare Variable Dvpds Integer;
Declare Variable Dvtmp Integer;
begin

 dvPDs = DsCreate();
 dvTmp = DsLogMessage(:dvPDs);
 dvTmp = DsFree(:dvPDs);

end
создает лог-файл и добавляет в него запись...

hvlad
Разработчик Firebird
Сообщения: 1244
Зарегистрирован: 21 мар 2005, 10:48

Re: Использование STL в UDF на C++Builder

Сообщение hvlad » 15 май 2009, 14:13

Orso, ты this в курсе ? И как он "используется" в методах, к нему не обращающихся ?

INTEGER передаётся ссылкой, а не значением. Возьми исходники любой УДФ на С и посмотри как правильно объявлять пар-ры.

Tonal
Сообщения: 104
Зарегистрирован: 30 сен 2007, 13:42

Re: Использование STL в UDF на C++Builder

Сообщение Tonal » 15 май 2009, 14:32

Orso писал(а):
Врёшь. Либо сейчас либо в первом посте, поскольку при таких объявлениях они совпадать не могут...
Простите, в таком случае как Вы считаете метод, не работающий с полями объекта должен выполняться?
Если не должен, то врете именно Вы. Ибо он работает...
Вызов метода для некорректного указателя на объект - это UB. Соответственно возможно любое поведение. В том числе и "правильное". :)
Конкретно в случае вызова методов не обращающихся к полям объекта этот UB очень возможно так себя и поведёт.

Насчёт ответов здесь тебе сразу сказали, что ты напутал с типами.
Если заглянешь в примеры (Firebird_2_1\examples\udf), это становится очевидным.
К STL проблемы всяко не имеют отношения.

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1436
Зарегистрирован: 15 сен 2005, 09:05

Re: Использование STL в UDF на C++Builder

Сообщение Dimitry Sibiryakov » 16 май 2009, 14:49

Orso писал(а):Простите, в таком случае как Вы считаете метод, не работающий с полями объекта должен выполняться?
Во всех известных мне implementations - да, если только он не виртуальный или динамический. Как тебе уже сказали - это азы С++. Почитай же, наконец, что-нибудь о внутреннем устройстве объектов. Хотя бы справку к тому же билдеру.

Ответить