Здравствуйте, MuTPu4, Вы писали:
MTP>Здравствуйте, Воронков Василий, Вы писали:
ВВ>>Это уже не любой тип. MTP>То есть все проблемы от того, что я не могу передать в функцию с такой сомнительной сигнатурой rvalue или о чем идет речь?
MTP>P.S. Вообще, было бы интересно посмотерть на реализацию функции, "которая будет принимать любой тип".
Здравствуйте, _nn_, Вы писали:
__>Сойдет ?
Ясно. Про reflection в исходном сообщении речи не шло, это несколько меняет дело. Хотя, насколько необходима такая функциональности в C++ для меня не очевидно, но в любом случае удачи в этом проекте .
Здравствуйте, MuTPu4, Вы писали:
MTP>Здравствуйте, _nn_, Вы писали:
__>>Сойдет ? MTP>Ясно. Про reflection в исходном сообщении речи не шло, это несколько меняет дело. Хотя, насколько необходима такая функциональности в C++ для меня не очевидно, но в любом случае удачи в этом проекте .
Представьте, что можно передавать любой тип, работать с ним, а потом сохранить состояние.
Далее другая программа создает этот тип только из данных в виде байтов и может работать с ним.
(Допустим реализация типа находится в одной библиотеке (Dll), а 2 программы используют ее).
Здравствуйте, _nn_, Вы писали:
__>Здравствуйте, MuTPu4, Вы писали:
MTP>>Здравствуйте, _nn_, Вы писали:
__>>>Сойдет ? MTP>>Ясно. Про reflection в исходном сообщении речи не шло, это несколько меняет дело. Хотя, насколько необходима такая функциональности в C++ для меня не очевидно__>Представьте, что можно передавать любой тип, работать с ним, а потом сохранить состояние. __>Далее другая программа создает этот тип только из данных в виде байтов и может работать с ним. __>(Допустим реализация типа находится в одной библиотеке (Dll), а 2 программы используют ее). MTP>>, но в любом случае удачи в этом проекте .
Спасибо
Здравствуйте, _nn_, Вы писали: __>Без ссылок там все равно не обойтись.
и что? __>void f(int& i); __>Это out или in-out аргумент ? __>Без документации нельзя узнать.
Хаха*3 Это out-аргумент, ибо не константный. Если константный — то in. __>А как вы решаете эти проблемы: __>
Изучите библиотеку "Boost Concept Check Library (BCCL)" — и проблема отпадёт сама.
Хотя при большом Вашем желании она (проблема) может у Вас и остаться...
Про in/out-параметры мысль есть:
Семантика взаимодействия вызывающей и вызываемой сторон не исчерпывается примитивами in/out/inout, так же как и value/reference/const_reference.
Devil in details — примитивы маскируют замысел, что потворствует ошибкам.
Как оно бывает на самом деле:
Далее — вызывающая и вызываемая стороны именуются клиентом и сервером, для краткости.
Примеры — на С++, хотя без труда их можно перевести на практически любой язык.
Если кого-то возмущают глобальные переменные — представьте себе, что это всё члены одного объекта одного класса. И клиент, и сервер — методы этого объекта.
Я привожу дистиллированные примеры для краткости и ясности; в жизни всё может выглядеть не так прозрачно, хотя и с теми же самыми эффектами.
1) Рандеву. Клиент и сервер выполняют совместную работу над одним экземпляром данных. Серверу может быть предоставлен некоторый интерфейс объекта (например, только константные члены).
void foo(ostream& ost)
// очевидно, что ostream - не value-тип, поэтому говорить об inout здесь сложно
// (значение туда-сюда не передаётся)
{
ost << "hello";
cout << endl;
// в результате, если ost и cout - одно лицо, то ost будет очищен (endl вызывает flush)
}
Как клиент может выполнять совместную работу? да через callback-функции, например. Или ещё через какие-то побочные эффекты.
Самая простая и естественная реализация — передача по ссылке (константной или нет).
2) Передача значения. Клиент рассчитывает, что сервер разрывает связь между клиентским и серверным экземплярами данных.
Сервер не может модифицировать клиентский объект. Модификации клиентского объекта не отражаются на сервере.
// дистиллированный пример модификации (вместо int можете подставить какой-нибудь тяжеловесный объект)void foo(int/*const&*/ fnf, int* hack) // раскомментируйте, чтобы взорвалось
{
int x = fnf;
++(*hack);
int y = fnf;
assert(x == y);
}
int main()
{
int x;
foo(x, &x);
}
Самая простая реализация — принудительное создание копии (aka передача по значению). И поэтому иногда неэффективная.
Во многих случаях достаточно передавать по константной ссылке (причём обе стороны должны соблюдать аккуратность).
Изощрённая реализация — механизм copy-on-write. То есть объект передаётся посредством умной ссылки, и любая попытка модификации приводит к расщеплению копий.
3) Обязательное возвращение значения.
Если экземпляр клиента уже существует, то он заведомо не совпадает с экземпляром сервера, откуда происходит однократная передача значения.
string g;
string foo()
{
string tmp = "(";
tmp += g;
tmp += ")";
return tmp;
}
void foo2(string& dst) // по неопытности сделали рандеву
{
dst = "[";
dst += g;
dst += "]";
}
void foo3(string& dst)
{
string tmp = "{";
tmp += g;
tmp += "}";
// ошибочка (см.ниже)
}
void foo4(string& dst)
{
string tmp = "{";
tmp += g;
tmp += "}";
dst = tmp;
}
int main()
{
g = "hello";
g = foo(); // "(hello)"
// пример практически идентичен предыдущему: там тоже создаётся временный объект
string tmp; foo2(tmp); g = tmp; // "[(hello)]";
// а вот пример некорректной реализации: не обеспечили изоляцию
foo2(g); // "[[]";
// багфикс на стороне сервера
foo3(g); // "[[]" - изолировать изолировали, а присвоить в конце забыли
foo4(g); // "{[[]}" - теперь всё правильно
}
Языки обеспечивают изоляцию через временный объект (размещённый на стеке или в регистре — не важно) и иногда позволяют оптимизировать копирование (RVO, NRVO). Но только для единственного параметра (return) и исключительно по прихоти компилятора.
Чистоплотный выход — возвращать кортежи вместо разрозненных retval-параметров — может стоить довольно дорого и не всегда удобен.
pair<string,int> foo()
{
string s = "{";
s += rand()%2 ? "hello" : "goodbye";
s += "}";
int x = s.size();
return make_pair(s,x);
}
int main()
{
string s; int x;
tie(s,x) = foo();
}
4) Необязательное возвращение значения.
Отличается от предыдущего тем, что значение может быть присвоено от 0 до 1 раза, по обстоятельствам.
Посредством return такое уже выразить сложно — разве что через бросок исключения.
Самая простая реализация — передавать ссылку и быть аккуратным.
5) Наконец, загадочный in-out. За ним может скрываться либо рандеву, либо экономичный способ сделать передачу исходного значения и обязательное/необязательное возвращение нового значения.
Обёртки параметров играют две роли
— обеспечивают подходящий транспорт (передачу копии или ссылки; COW и отложенное присваивание)
— выполняют проверки (было ли присвоено значение out-параметру, например)
Здравствуйте, Centaur, Вы писали:
C>Здравствуйте, Pavel Chikulaev, Вы писали:
C>
int * f(int *);
PC>>И что делать с обоими указателями? Удалять или нет?
C>Если это C++, а не C, то тут довольно понятно. C>Если бы функция хотела, чтобы мы отдали ей int во владение, она бы принимала auto_ptr<int>. Раз оно не так, мы должны его убить сами. Напротив, если бы функция хотела вернуть нам int, чтобы мы его потом удалили, она бы вернула его через auto_ptr<int>. Это не так, значит, вернутый указатель не наш, и удалять его не нам
+1. Или shared_ptr. Но обычно следует передавать ссылку если не происходит передача владения и объект всегда существует.
Только библиотек, в которых применяется это правило не так много (а точнее очень мало), так что документацию на всякий случай придется посмотреть (часто даже там не пишут про это : ( ). А хотелось бы этого не делать...
Здравствуйте, sergey_shandar, Вы писали:
_>Здравствуйте, _nn_, Вы писали:
__>>Спасибо всем за комментарии.
__>>4. Унифицированная передача аргументов.
_>Раз пошла такая пьянка, то как на счет типа результата функции? В COM обычно это оформляется как out<T>. Но, такой синтаксис _>
Здравствуйте, _nn_, Вы писали:
__>Насколько можно сделать перемещение эксклюзивным, т.е. без изменения самого класса ?
struct a
{
void q(){}
};
move_t<a> f()
{
a x;
x.q();
// Создание - явное, защита от самого себя :-)returnmove(x);
}
int main()
{
// move_t использует swap, поэтому для обмена нужно сначала создать объект.
// Если без изменения класса, то только так (я не знаю других вариантов эффективных):a y;move_ref(y) = f();// Или создавая сразу уже move_t<a> и используя операторы * и ->move_t<a> y1(f());
}
Здравствуйте, sergey_shandar, Вы писали:
_>Здравствуйте, _nn_, Вы писали:
__>>Насколько можно сделать перемещение эксклюзивным, т.е. без изменения самого класса ?
_>
_>struct a
_>{
_> void q(){}
_>};
_>move_t<a> f()
_>{
_> a x;
_> x.q();
_> // Создание - явное, защита от самого себя :-)
_> returnmove(x);
_>}
_>int main()
_>{
_> // move_t использует swap, поэтому для обмена нужно сначала создать объект.
_> // Если без изменения класса, то только так (я не знаю других вариантов эффективных):
_> a y;
_> move_ref(y) = f();
_> // Или создавая сразу уже move_t<a> и используя операторы * и ->
_> move_t<a> y1(f());
_>}
_>
Тут можно пойти еще по другому пути создать тип переменной, которая перемещаемая (moveable):
Здравствуйте, sergey_shandar, Вы писали:
_>Здравствуйте, _nn_, Вы писали:
_>Тут можно пойти еще по другому пути создать тип переменной, которая перемещаемая (moveable): _>
Здравствуйте, _nn_, Вы писали:
_>>MIT. Близкая к BSD и Boost. Не GPL __>Я не очень силен в лицензиях. __>Могу ли я этот код немного изменить для общего стиля библиотеки ?
Да, все что угодно. Главное что бы ко мне никаких претензий, если из за этого куска кода у кого то деньги со счета не пропали и т.п.
Здравствуйте, sergey_shandar, Вы писали:
_>Здравствуйте, _nn_, Вы писали:
_>>>MIT. Близкая к BSD и Boost. Не GPL __>>Я не очень силен в лицензиях. __>>Могу ли я этот код немного изменить для общего стиля библиотеки ? _>Да, все что угодно. Главное что бы ко мне никаких претензий, если из за этого куска кода у кого то деньги со счета не пропали и т.п.
Ок, включу в библиотеку.
Хотите я вас в разработчики добавлю ?
На данный момент будут следущие типы:
in — для входных аргументов
out — для выходных аргументов
inout — для входных и выходных аргументов
ref — для ссылки на out/inout
cref — для ссылки на in (inout ?)
ret — для возврата функций
var — для обычных переменных
Здравствуйте, _nn_, Вы писали:
__>Хотите я вас в разработчики добавлю ?
На форума вашего проекта cpp-objects в Open Discussion есть встречное предложение Отвечайте туда, что бы не засорять RSDN.