Плагины, new и кактуси :(
От: sanjaa  
Дата: 03.10.08 10:29
Оценка:
Здравствуйте уважаемые!

Подскажите как быть с плагинами.
Есть у меня класс который по указателю передается с приложения в dll.
class IPlugin
{
public:
    IPlugin(void);
    virtual ~IPlugin(void);

 // злостная функция  :crash:       
    const bool    QuerySetVar(const string& name, const string& val) const;
 
    const string    QueryGetVar(const size_t var) const;

};


Dll вызывает функцию QuerySetVar в которую передает аргумент типа string.
В QuerySetVar аргумент присваивается новому объекту string который выделяется динамически.
Но после того как мое приложение уничтожаєт копию аргумента я получаю ошибку нарушения доступа в:

extern "C" static int __cdecl CheckBytes(
        unsigned char * pb,
        unsigned char bCheck,
        size_t nSize
        )


Подозреваю что что так делать нельзя.
Колеги помогите разобраться пожалуйста. Посоветуйте литературу или статьи по даному поводу.
Как мне с dll поменять значение динамического объект string в exe
plugin
Re: Плагины, new и кактуси :(
От: sof.bix Россия http://byterix.net
Дата: 03.10.08 10:45
Оценка:
Здравствуйте, sanjaa, Вы писали:

S>Подозреваю что что так делать нельзя.

S>Колеги помогите разобраться пожалуйста. Посоветуйте литературу или статьи по даному поводу.
S>Как мне с dll поменять значение динамического объект string в exe

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

Это очень сложно. Проще поступить стандартным средством:
не работать в интерфейсе плагина с string ваще!
В конце концов ваш плагин нельзя будет писать например на билдоре или делфи.
Выход очень прост: работать с указателем на строку в конечном интерфейсе. Т.е. хранить строку в том же string, но менять как char*
Re[2]: Плагины, new и кактуси :(
От: sanjaa  
Дата: 03.10.08 11:00
Оценка:
Здравствуйте, sof.bix, Вы писали:

SB>Здравствуйте, sanjaa, Вы писали:


S>>Подозреваю что что так делать нельзя.

S>>Колеги помогите разобраться пожалуйста. Посоветуйте литературу или статьи по даному поводу.
S>>Как мне с dll поменять значение динамического объект string в exe

SB>объекты нужно создавать там где они должны удаляться.

SB>Если вы в dll меняете значение, то в ней же удаляется старая память, выделеная в программе (это уже невалидно) и создается новая.
SB>В итоге вы должны удалить данную строку не через программу а через DLL.

SB>Это очень сложно. Проще поступить стандартным средством:

SB>не работать в интерфейсе плагина с string ваще!
SB>В конце концов ваш плагин нельзя будет писать например на билдоре или делфи.
SB>Выход очень прост: работать с указателем на строку в конечном интерфейсе. Т.е. хранить строку в том же string, но менять как char*

Спасибо за помощь sof.bix.
Но! Если я Вас верно понял то вся проблема в том что аргумент string ?
Я пробавал и с const char*
const bool        QuerySetVar(const size_t index, const char* str) const


результат тот же.
Может быть потому что реализация функции QuerySetVar выделяет память ?
Re[2]: Плагины, new и кактуси :(
От: Nikita123 Россия  
Дата: 03.10.08 11:24
Оценка:
Здравствуйте, sof.bix, Вы писали:

S>>Подозреваю что что так делать нельзя.

S>>Колеги помогите разобраться пожалуйста. Посоветуйте литературу или статьи по даному поводу.
S>>Как мне с dll поменять значение динамического объект string в exe

SB>объекты нужно создавать там где они должны удаляться.

SB>Если вы в dll меняете значение, то в ней же удаляется старая память, выделеная в программе (это уже невалидно) и создается новая.
SB>В итоге вы должны удалить данную строку не через программу а через DLL.
C этим я согласен. Проблем не будет.

SB>Это очень сложно. Проще поступить стандартным средством:

SB>не работать в интерфейсе плагина с string ваще!
А это зачем?

SB>В конце концов ваш плагин нельзя будет писать например на билдоре или делфи.

А может быть и не надо писать на Билдере или Дельфи?

SB>Выход очень прост: работать с указателем на строку в конечном интерфейсе. Т.е. хранить строку в том же string, но менять как char*

А это уже полный бред!
Желаю успеха,
Никита.
Re[3]: Плагины, new и кактуси :(
От: sanjaa  
Дата: 03.10.08 11:37
Оценка:
Здравствуйте, Nikita123, Вы писали:

N>Здравствуйте, sof.bix, Вы писали:


S>>>Подозреваю что что так делать нельзя.

S>>>Колеги помогите разобраться пожалуйста. Посоветуйте литературу или статьи по даному поводу.
S>>>Как мне с dll поменять значение динамического объект string в exe

SB>>объекты нужно создавать там где они должны удаляться.

SB>>Если вы в dll меняете значение, то в ней же удаляется старая память, выделеная в программе (это уже невалидно) и создается новая.
SB>>В итоге вы должны удалить данную строку не через программу а через DLL.
N>C этим я согласен. Проблем не будет.

SB>>Это очень сложно. Проще поступить стандартным средством:

SB>>не работать в интерфейсе плагина с string ваще!
N>А это зачем?

SB>>В конце концов ваш плагин нельзя будет писать например на билдоре или делфи.

N>А может быть и не надо писать на Билдере или Дельфи?

SB>>Выход очень прост: работать с указателем на строку в конечном интерфейсе. Т.е. хранить строку в том же string, но менять как char*

N>А это уже полный бред!

Здраствуйте, Nikita123 как тогда быть ?
Если какой то другой способ ? Может есть где что то почитать ?

Зарание спасибо.
Re: Плагины, new и кактуси :(
От: Рома Мик Россия http://romamik.com
Дата: 03.10.08 12:45
Оценка: 1 (1)
Здравствуйте, sanjaa, Вы писали:

Не использовать stl типы в интерфейсе плагина. И соблюдать правило: кто память выделял, тот ее и освобождает.
Например ты можешь сделать так:
bool SetVar(char const * name, char const * val); // тут я думаю с реализацией проблем быть не должно
char const * GetVar(char const * name) const
{
static std::string result;
result = RealGetVar(name);
return result.c_str();
}

И в документации предупредить, что следующий вызов GetVar портит буфер, который вернул предыдущий вызов, так что при необходимости хранения — скопировать. Для многопоточного случая использовать thread local storage, а логику оставить такую же.

Другой вариант:
char const * GetVar(char const * name) const
{
static std::vector<std::string> result;
result.push_back(RealGetVar(name));
return result.back().c_str();
}
Re[3]: Плагины, new и кактуси :(
От: sof.bix Россия http://byterix.net
Дата: 03.10.08 12:48
Оценка:
Здравствуйте, sanjaa, Вы писали:

S>результат тот же.

S>Может быть потому что реализация функции QuerySetVar выделяет память ?


так не вы писали QuerySetVar ? А как вы установили что именно она является проблемной? а не QueryGetVar?
Re[2]: Плагины, new и кактуси :(
От: BitField Украина http://lazy-bitfield.blogspot.com
Дата: 03.10.08 13:26
Оценка:
Здравствуйте, Рома Мик, Вы писали:

РМ>Здравствуйте, sanjaa, Вы писали:


РМ>Не использовать stl типы в интерфейсе плагина. И соблюдать правило: кто память выделял, тот ее и освобождает.


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

РМ>Другой вариант:

РМ>
РМ>char const * GetVar(char const * name) const
РМ>{
РМ>static std::vector<std::string> result;
РМ>result.push_back(RealGetVar(name));
РМ>return result.back().c_str();
РМ>}
РМ>


Никаких гарантий, что при добавлении нового элемента в вектор предыдущие строки не перевыделят память, нет.
Нужен std::list или std::deque (на счет второго -- не уверен)
Re[3]: Плагины, new и кактуси :(
От: vayerx  
Дата: 03.10.08 14:51
Оценка:
Здравствуйте, BitField, Вы писали:

РМ>>Не использовать stl типы в интерфейсе плагина. И соблюдать правило: кто память выделял, тот ее и освобождает.

BF>А может, просто удостовериться, что и библиотеки, и основное приложение используют один и тот-же разделяемый рантайм

... и аккуратно положить перед собой грабли? нужно объяснять почему? =)

BF>Никаких гарантий, что при добавлении нового элемента в вектор предыдущие строки не перевыделят память, нет.

BF>Нужен std::list или std::deque (на счет второго -- не уверен)

deque для такой реализации не нужен — удаление из середины может приводить к реаллокации.
Re[3]: Плагины, new и кактуси :(
От: Рома Мик Россия http://romamik.com
Дата: 03.10.08 19:14
Оценка:
Здравствуйте, BitField, Вы писали:

BF>А может, просто удостовериться, что и библиотеки, и основное приложение используют один и тот-же разделяемый рантайм,

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

РМ>>Другой вариант:

РМ>>
РМ>>char const * GetVar(char const * name) const
РМ>>{
РМ>>static std::vector<std::string> result;
РМ>>result.push_back(RealGetVar(name));
РМ>>return result.back().c_str();
РМ>>}
РМ>>

BF>Никаких гарантий, что при добавлении нового элемента в вектор предыдущие строки не перевыделят память, нет.
BF>Нужен std::list или std::deque (на счет второго -- не уверен)
Ты прав, я ошибся. Лучше всего list.
Re[2]: Плагины, new и кактуси :(
От: sanjaa  
Дата: 03.10.08 19:35
Оценка:
Здравствуйте, Рома Мик. Спасибо что откликнулись

РМ>bool SetVar(char const * name, char const * val); // тут я думаю с реализацией проблем быть не должно

Именно здесь и проблема!

Привожу тестовый клас:
class IPlugin
{
public:
    IPlugin(void) {m_pTest = new string;}
    virtual ~IPlugin(void);

    const bool        QuerySetVar(const size_t index, const char* str)
    {

        // здесь релокейт
        *m_pTest = str;    
        return true;
    }

    void    DeleteTest()
    {
        // crash!!
        delete m_pTest;
    }

private:
    string*            m_pTest;
};


в апп вызывает функцию с dll в которую передаю интерфейс IPlugin*

IPlugin pl;

// визов библиотечной функции которая вызывает QuerySetVar
(dll_function)(&pl);

// после етой строчки креш!
pl.DeleteTest();


в dll:

void dll_function(IPlugin* p)
{
  const char* str = "Test for string......";
  p->QuerySetVar(0,str);
}


Подскажите как уйти от релокейт памяти ?
Re[3]: Плагины, new и кактуси :(
От: superlexx  
Дата: 03.10.08 21:09
Оценка: 1 (1)
Велосипед изобретать не надоело? Когда надоест, посмотрите, как это в COM делается.
Re[3]: Плагины, new и кактуси :(
От: Аноним  
Дата: 03.10.08 22:25
Оценка:
N>А может быть и не надо писать на Билдере или Дельфи?
SB>>Это очень сложно. Проще поступить стандартным средством:
SB>>не работать в интерфейсе плагина с string ваще!
N>А это зачем?
Исключительно по секрету скажу — std::string разные между разными студиями, и просто между разными STL. Если автор претендует на плагины как плагины, т.е. разработанные сторонники разработчиками компоненты, реализующие его интерфейс, неважно какими средствами, ему придеться объявить полностью STL-независимый интерфейс. В простейшем случае char *, хотя лучше конечно заюзать обертку. Если речь про виндовс-онли — BSTR.
Re: Плагины, new и кактуси :(
От: sanjaa  
Дата: 04.10.08 08:42
Оценка:
Спасиба всем!
Буду рыть в сторону COM!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.