2012-07-03 2 views
2

Я не могу понять это. Похоже, я пропустил что-то простое? Что я положил в MakePointToSameValue таким образом, что в точке (1)Как сделать все копии shared_ptr равными другому shared_ptr?

  • как b.ptr и c.ptr указывают на то же самое, как a.ptr
  • другими словами, a.ptr.get() == b.ptr.get() == c.ptr.get()
  • значение первоначально указал по b.ptr и c.ptr удаляется

?

struct Test 
{ 
public: 
    Test(int val) : 
    ptr(std::make_shared<int>(val)) 
    { 
    } 

    void MakePointToSameValue(Test& other) 
    { 
    //what do I put here? 
    //other.ptr = this->ptr; //doesn't do it 
    } 

private: 
    std::shared_ptr<int> ptr; 
}; 

Test a(0); 
Test b(5); 
Test c(b); 

b.MakePointToSameValue(a); 

//(1) 

Копирование PTR не работает, так как он не изменяет с (ну, c.ptr имеет это RefCount уменьшается на единицу). Обратите внимание, что я использую int только для упрощения, но он должен работать для не подлежащих копированию типов.

Почему? У меня есть класс, представляющий значения, любые типы значений, для использования в каком-то компиляторе. Фактическое значение, а также то, как оно хранится, известно, когда оно создается. Единственное, что известно, это тип. Таким образом, класс хранит shared_ptr, содержащий местозаполнитель для значения, определенного позже (соответствует компиляции аргументов определения функции при передаче как указателя или ссылки: компилятор знает только тип, не более того). Во время выполнения местозаполнитель должен быть заменен фактическим значением.

Редактировать свежее начало дня, придумал это. Я знал, что это просто.

void MakePointToSameValue(Test& other) 
{ 
    other.ptr.swap(ptr); 
    ptr.reset(); 
    ptr = other.ptr; 
} 

Дополнительный вопрос: есть ли работа над тем, что ожидается для любого стандартного совместимого указателя?

+0

Для чего именно? –

+4

Похоже, вам нужны два уровня косвенности. –

+0

@CatPlusPlus см. Последний абзац – stijn

ответ

3

Здесь вам нужны два уровня косвенности. Хотя вы правы, что все объекты shared_ptr указывают на общий блок метаданных, содержащий счетчик и указатель на фактическое значение, если вы попытались обновить этот блок, чтобы указать на другой объект, теперь у вас будет два блока метаданных, указывающих к одному и тому же значению, каждый из которых имеет свою собственную идею о том, каков счетчик ссылок.Существует правильный номер (в том смысле, что он соответствует счету ссылок) объектов shared_ptr, используя каждый блок метаданных, поэтому счетчик для каждого блока в конечном итоге достигнет нуля, но нет способа узнать, какой блок является последним блоком для достижения количества от нуля (и, следовательно, должно удалить значение). Таким образом, shared_ptr разумно не позволяет изменять указатель объекта внутри метаданных. Вы можете связать только shared_ptr с новым блоком метаданных, новым счетчиком, новым объектом. И другие указатели на один и тот же объект не затрагиваются.

Правильный способ сделать это - использовать второй слой косвенности (shared_ptr<shared_ptr<int> >). Таким образом, есть только один блок метаданных и ровно один счетчик для каждого объекта. Ваше обновление происходит с промежуточным shared_ptr.

1

Ну, насколько я понимаю ваши требования, shared_ptr не содержит таких механизмов; и не было бы обычного типа. Если вы хотите этого поведения, вам придется самому его закодировать. Мое предложение: добавьте приватный статический std::list<std::weak_ptr<Test>> registry; зарегистрируйте каждый экземпляр Test, добавив его в список registry в конструкторе и обязательно удалите его в деструкторе.

Затем используйте этот реестр в MakePointToSameValue, чтобы перебрать все экземпляры и сбросить значение ptr.

Если вы заинтересованы в эффективности и имеете несколько экземпляров больше, чем три, вы хотите заменить list на unordered_set; и, возможно, используйте unique_ptr, а не shared_ptr в вашем классе Test.

Ответ на дополнительный вопрос: нет, это не сработает. Посмотрите документацию reset(): он сбрасывает один конкретный экземпляр shared_ptr: он ничего не делает с (и ничего не знает) о других экземплярах. Когда счетчик ссылок в контрольном блоке достигает нуля, он дополнительно уничтожает указателя, но это все.

+0

y u 'std :: list'? Это просто глупо. Например, вы можете извлечь и добавить O (1) с помощью 'unordered_set'. – Puppy

+0

Да. Является ли это более эффективным, зависит от количества экземпляров, которые stijn не дал нам никакого результата: если это всего лишь три, моя ставка по-прежнему остается в списке. В противном случае, конечно. –

+0

Хм, я думал, что это должно быть возможно с shared_ptr? Я имею в виду, он содержит все необходимое (все копии имеют один и тот же объект указателя/refcount внутри), я просто не могу понять, как использовать его для использования atm. – stijn

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