Можно ли ограничить использование экземпляров классов только временными? - PullRequest
9 голосов
/ 31 января 2011

возможно ли ограничить использование экземпляров классов только в качестве значений (например, временных)?

например, у меня есть класс Wrapper, конструктор которого принимает A const& и сохраняет эту ссылку в своем члене.Это опасно, потому что время жизни экземпляра Wrapper не может превышать время жизни экземпляра A, но это нормально, если Wrapper равно temporary.

Ответы [ 6 ]

4 голосов
/ 31 января 2011

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

Тем не менее, вы можете сделать все конструкторы приватными и сделать функцию друга, которая возвращает значение.Это должно сработать.

4 голосов
/ 31 января 2011

Я не думаю, что это будет безопасно:

const A &a = YourClass( tmp );

YourClass в данном случае это класс, который вы ищете, который разрешает только временные экземпляры, tmp это временное значение, которое выперейти к конструктору.
Возможно (то есть: безопасное, определенное поведение) иметь постоянную ссылку на временное (то есть: a), но сам временный объект (такой экземпляр YourClass) получил ссылкуна tmp, который больше не действителен после вычисления этого выражения.

3 голосов
/ 31 января 2011

Не совсем тот ответ, который вы ищете, но задумывались ли вы о слабых указателях? (например, boost::weak_ptr). В этом случае исходный A будет храниться в shared_ptr, а конструктор Wrapper принимает weak_ptr. Преимущество этого подхода в том, что перед каждым использованием weak_ptr вы можете попытаться набрать lock(), что даст вам shared_ptr - в случае неудачи вы знаете, что A пропало и Wrapper не может функционировать ... Но он обрабатывается чисто ...

1 голос
/ 19 февраля 2017

Это может помочь, если в вашем классе нет открытых данных.

По сути, идея состоит не в том, чтобы ограничить конструкцию оболочки, а в том, чтобы использовать экземпляры можно (как вы сказали) только до тех пор, пока они являются временными значениями. Этого можно достичь, перегрузив все методы и удалив (или сделав их приватными) те, которые ссылаются на const &.

Вот простой пример:

class Wrapper
{
public:
    Wrapper() = default;
    Wrapper(const std::string& name) : name(name) {}
    void process() && { std::cout << "Greetings from " << name << std::endl; }
    // Only temporary instances of this class are allowed!
    void process() const & = delete;

private:
    std::string name;
};

И некоторые варианты использования:

Wrapper("John").process(); // intended use case
Wrapper j; // create whatever you want
j.process();  // error C2280: 'void Wrapper::process(void) const &': attempting to reference a deleted function
std::move(j).process(); // this is still possible
const Wrapper& t = Wrapper();  // bind the temporary to a const reference - not a problem because ...
t.process(); // error C2280: 'void Wrapper::process(void) const &': attempting to reference a deleted function

Очевидные недостатки:

  • Вы должны перегрузить каждую публичную функцию-член.
  • Сообщение об ошибке задерживается и не очень информативно.

Подобное было сделано в стандарте. Процедуры make для std :: reference_wrapper не принимают временные значения .

Обратите внимание, что они рассмотрели еще одну тонкость: перегрузка использует const T && вместо T &&. Это может быть важно и в нашем случае. Например, если ваша обертка специально разработана для того, чтобы ее нельзя было скопировать, и вы используете процедуры make, такие как

const Wrapper make_wrapper();

вместо

Wrapper make_wrapper();

В этом случае вы можете заменить

void process() &&;

по

void process() const &&;
1 голос
/ 31 января 2011

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

0 голосов
/ 31 января 2011

Да, вы могли бы.

Вы бы сделали конструктор и обычный конструктор копирования / назначить приватным, но сделали бы семантику перемещения значения r (C ++ 0x) общедоступной.

Выбудет иметь статический или дружественный конструктор для создания временного.

В 2003 C ++ вы также сможете использовать это для привязки к константной ссылке.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...