Цель c — Как смешать общие указатели C ++ и ссылки на объекты

У меня есть следующий код, который использует объект 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 в качестве ссылки), но все же предотвратить освобождение общего указателя до завершения блока?

6

Решение

Нет способа сделать это, оставив интерфейс 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.
});
}
3

Другие решения

Вы должны сами управлять ссылками:

#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;
}
1

Вы хотите передать право собственности с 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));
0
По вопросам рекламы [email protected]