У меня есть следующий код, который использует объект C ++ класса Datum
внутри функции Objective-C work
:
void work(const Datum &datum) {
dispatch_async(dispatch_get_main_queue(), ^{
// Work with datum.
});
}
Этот код вызывается с экземпляром, который на самом деле boost::shared_ptr<Datum>
т.е.
boost::shared_ptr<Datum> the_datum(new Datum());
work(*the_datum);
В этой ситуации возможно, что экземпляр the_datum
освобождается до запуска блока внутри work
(призыв к dispatch_async
выполняет асинхронную операцию на datum
это выполняется позже; вызов и, следовательно, функция work
вернись немедленно). Это, очевидно, приводит к катастрофе.
Одним из решений может быть не передавать ссылку на work
, но boost::shared_ptr<Datum>
вместо. Но могут быть ситуации, когда предпочтение отдается ссылкам, см., Например, эта тема. Есть ли способ сохранить интерфейс work
(то есть проход datum
в качестве ссылки), но все же предотвратить освобождение общего указателя до завершения блока?
Нет способа сделать это, оставив интерфейс work()
то же самое, и передать ссылку на datum
, Там нет никакого способа использовать datum
чтобы предотвратить уменьшение количества ссылок. Рассмотрим следующую глючную программу:
#include <memory>
int main () {
std::shared_ptr<int> p1(new int);
int &x = *p1;
std::shared_ptr<int> p2(&x);
}
Этот код падает с двойным свободным, потому что shared_ptr<>
Структура управления не следует за указателем на объект, но сопровождается shared_ptr<>
сам.
Что вы можете сделать, это изменить work()
взять shared_ptr()
, но добавьте еще немного кода в блок, переданный dispatch_async()
так что он может использовать ссылку в этом коде. Поскольку вы передаете владение асинхронной подпрограмме, вы должны использовать unique_ptr<>
вместо. Я знаю, что такое Objective-C, поэтому этот синтаксис может быть неправильным:
void work(std::unique_ptr<Datum> &datumptr_ref) {
__block std::unique_ptr<Datum> datumptr(std::move(datumptr_ref));
dispatch_async(dispatch_get_main_queue(), ^{
Datum &datum = *datumptr
// Work with datum.
});
}
Вы должны сами управлять ссылками:
#include <iostream>
#include <memory>
extern "C" {
typedef struct TagShared Shared;
Shared* allocate(const std::shared_ptr<int>& ptr) {
return (Shared*) new std::shared_ptr<int>(ptr);
}
void deallocate(Shared* shared) {
delete (std::shared_ptr<int>*)shared;
}
} // extern "C"
int main()
{
std::shared_ptr<int> s(new int(1));
Shared* p = allocate(s);
// Inside Dispatch
// No C++ but similar defined for TagShared
std::cout << **(std::shared_ptr<int>*)p << std::endl;
deallocate(p);
return 0;
}
Вы хотите передать право собственности с std::unique_ptr
что-то вроде этого:
void work(std::unique_ptr<Datum> datum) {
dispatch_async(dispatch_get_main_queue(), ^{
// Work with datum.
});
}
std::unique_ptr<Datum> the_datum(new Datum());
work(std::move(the_datum));