2014-01-15 3 views
4

Рассмотрима кодаunique_ptr использования для старых функций

struct Resource 
{ 
    Resource() 
    { 
     std::cout << "C"; 
    } 
    ~Resource() 
    { 
     std::cout << "D"; 
    } 
}; 

void allocate(Resource **p) 
{ 
    *p = new Resource(); 
} 

int main() 
{ 
    Resource *p = nullptr; 
    allocate(&p); 
    std::unique_ptr<Resource> uptr(p); 

    //stuff 
} 

Предполагая, что «выделить» функция широко используется в унаследованном коде в нескольких местах вызова, основная функция показывает попытку использовать unique_ptr управлять выделенным ресурсом. Проблема возникает, когда другой программист в команде пишет код, подверженный ошибкам, после «allocate» и до того, как «unique_ptr» получит его.

Таким образом, одно решение, которое приходит на ум, чтобы написать код, который использует оператор запятой следующим

std::unique_ptr<Resource> up((allocate(&p), p)); 

Есть еще один разумный способ справиться с этой ситуацией? Основная проблема состоит в том, чтобы сделать alllocation и владение в качестве атомной операции.

+0

В этом конкретном случае у вас может быть функция, которая просто возвращает указатель: 'Resource * allocate() {Resource * result; выделяют (& результат); результат возврата; } ', а затем используйте эту функцию:' std :: unique_ptr up (allocate()); 'Ваша настоящая проблема более общая, и если да, можете ли вы изменить свой вопрос, чтобы включить случаи, которые не могут быть решены так? – hvd

+0

как обматывать функцию 'allocate' так, чтобы она вернула перемещенный' std :: unique_ptr'? – Alex

+0

Как я уже упоминал, allocate - это сильно используемая функция, и я не вижу ее подписи сразу. Итак, в том смысле, что это медленное, но устойчивое принятие концепций C++ 11 в продукте – Chubsdad

ответ

0

Честно говоря, мне очень нравится ваше решение для запятой. Конечно, вам все равно нужны ваши забывчивые программисты с исключительным удовольствием, чтобы не забыть использовать его, поэтому он не работает как исправление для всех.

Фактически, на этой основе их нет.

1

Типичный способ сделать это, чтобы вернуть unique_ptr из перегруженной функции:

std::unique_ptr<Resource> allocate() 
{ 
    return std::unique_ptr<Resource>(new Resource()); 
} 
+0

Об изменении: не является ли конструктор 'unique_ptr' автоматически вызванным? – Dan

+0

[Нет, конструктор является «явным».] (Http://coliru.stacked-crooked.com/a/cb91b33a7f0958bc «Демо в Coliru») – Casey

+0

причина для downvote заключается в том, что OP не хочет меняться подпись вызова. – Alex

2

Для плавную перехода, создают перегрузку allocate:

template <typename T> 
void allocate(std::unique_ptr<T>* p) { 
    T* raw; 
    allocate(&raw) 
    p->reset(raw); 
} 

Существующие сайты вызовов будет продолжаться работать без изменений. Когда вы обновляете сайт вызова, вы заменяете необработанный указатель на unique_ptr и удаляете любую строку, освобождающую ресурс, но в остальном код остается неизменным. (Замените места, куда передается необработанный указатель с .get().)

+2

Я думаю, что я просто вернул значение 'unique_ptr' по значению и избавился бы от странного соглашения о вызове pass-pointer-to-return-value. – Casey

+0

@ Casey хорошо, он сказал «плавный переход» - 'std :: unique_ptr uptr; allocate (&uptr); 'vs' Resource * p; allocate (&p); ' – melak47

Смежные вопросы