#cpp #visual_cpp #dll
Читал не раз, что передача по ссылке - это просто передача указателя, который внутри функции автоматически разыменовывается. Насколько это верно? Например, я написал такую dll (в Visual Studio): extern "C" void __declspec(dllexport) test(int* i) { cout << "test(" << *i << ")\n"; (*i)++; } И вот такую программу для работы с ней: typedef void (*myfunc)(int&); int main() { HMODULE dll; if ((dll = LoadLibrary("Dll.dll")) != NULL) { myfunc f = (myfunc)GetProcAddress(dll,"test"); int q = 5; cout << "q = " << q << endl; f(q); cout << "q = " << q << endl; FreeLibrary(dll); } } Все работает, получается что я и хотел: q = 5 test(5) q = 6 Только насколько на эту передачу по ссылке как указателя можно полагаться? Какие могут быть неприятности? И еще сразу хотел спросить, у меня, например, в dll используется cout - это тот же cout, что и в основной программе или нет? А если я передам на него указатель - то все равно ведь будет использоваться код в dll, а не в программе? Или если я выделю в dll память, то как ее правильно освободить в программе? например, если я верну unique_ptr в функции в dll?
Ответы
Ответ 1
Нет, не тождественна. Указатель - это физический объект в памяти, занимающий место и умеющий значение. Ссылка - это просто синоним имени объекта, для хранения которого не выделяется дополнительной памяти. Другими словами, когда Вы оперируете ссылками, то можете представить что работаете с той же переменной, что и при объявлении (для компилятора нет разницы в этом случае). В случае использования динамически подключаемых библиотек, строгой рекомендацией является использование С интерфейса (в С существуют только указатели), дабы иметь возможность работать с библиотекой из других языков. Не стоит в данном случае возвращать std::unique_ptr<>. Также насчёт выделения памяти, если Вы выделяете память внутри библиотеки, то внутри и должны освобождать. Использование умных указателей в данном случае - современный подход слежения за памятью. Старайтесь строго избегать явных вызовов delete. Прежде всего стоит определиться нужно действительно нужно ли выделять память внутри библиотеки или допустимо передать ей буфер и его размер. Если всё же библиотеке нужно выделять память и возвращать её, то допустим мы имеем две функции: void* dll_alloc(size_t size) и dll_free(void* ptr) Тогда для удобной работы и автоматическим освобождением памяти, можем использовать следующее: std::shared_ptrdllMemory(dll_alloc(1024), dll_free); В таком случае, нам не нужно явно вызывать dll_free. Ответ 2
Вы не имеете права предполагать, что ссылка внутри устроена как указатель. Декларация функции, отличающаяся от её настоящего определения, есть undefined behaviour. То, что это «работает» — случайность, как и при любом UB. С усложнением программы и/или изменением настроек компилятора возможны любые неприятные сюрпризы. То, что в приведённых вами словах верно — это то, что ссылка ведёт себя во многом как автоматически разыменуемый указатель. Важное семантическое отличие между указателем и ссылкой — ссылку нельзя переназначить, и она обязательно указывает на какой-то объект (в корректной программе). То есть, не существует «null-ссылок».Ответ 3
По первой части - думаю, что в стандарте никаких указаний нет и не должно быть. Откровенно говоря, не думаю, что если такая передача в VC++ получается успешно, то в какой-то момент перестанет быть таковой... но вполне допускаю, что другой компилятор может работать и иначе. Поэтому, как мне кажется, в пределах одного компилятора - грубо говоря, в своей программе - пользоваться в принципе можно... отдавая отчет в том, что теоретически это может сломаться в каких-то будущих версиях. Но не проще ли использовать лишний уровень косвенности? Просто написать функцию-посредник, принимающую ссылку, но вызывающую функцию DLL с передачей ей адреса этой ссылки? По второй части - если вы использовали статические библиотеки, то да, cout у вас разные, если же динамический runtime - то, думаю, один и тот же, из динамических библиотек. По поводу памяти - насколько я помню советы опытных :), крайне желательно освобождать память там, где она была выделена. Но как с этим согласовать те же интеллектуальные указатели или что-то иное - простой и надежный способ в голову пока не приходит.
Комментариев нет:
Отправить комментарий