Доступ к copy-ctor через отдельный метод
От: _hum_ Беларусь  
Дата: 23.03.22 09:47
Оценка:
Появилась задача добавить уже существующему классу возможность клонирования его объектов (изначально такой возможности не было — копирование было запрещено). Поскольку класс довольно массивный, то есть опасения, что при написании конструкторов копирования будут ошибки. По этой причине, не хотелось бы открывать эти конструкторы копирования для полного доступа, тем самым открывая возможность их неявного вызова в коде. Хотелось бы, чтобы вызовы конструкторов были только для задачи клонирования, и соответственно, осуществлялись явно. На ум тут пришло следующее решение:
class CA
{
    std::unique_ptr<int> m_ui;
    //^^^^^^^^^^^^^^^^^^^^^^^
    explicit 
    CA(const CA& o)
        :m_ui(new int(*o.m_ui))
    {}
    //-----------------------
public:
    //-----------------------
    CA(int i):
      m_ui(new int(i))
    {}
    //-----------------------
    CA(CA&&)=default;
    //-----------------------
    CA clone(){ return CA(*this);}
    //-----------------------
    int get(){return *m_ui;}
    //-----------------------
};

Но насколько оно соответствует заявленной цели, и может, есть что-нибудь красивее?
(И, на всякий случай, есть ограничения — в функции clone нельзя использовать работу с динамической памятью).

Заранее благодарен за советы.
Re: Доступ к copy-ctor через отдельный метод
От: Igore Россия  
Дата: 24.03.22 06:55
Оценка:
Здравствуйте, _hum_, Вы писали:

__>Появилась задача добавить уже существующему классу возможность клонирования его объектов (изначально такой возможности не было — копирование было запрещено). Поскольку класс довольно массивный, то есть опасения, что при написании конструкторов копирования будут ошибки. По этой причине, не хотелось бы открывать эти конструкторы копирования для полного доступа, тем самым открывая возможность их неявного вызова в коде. Хотелось бы, чтобы вызовы конструкторов были только для задачи клонирования, и соответственно, осуществлялись явно. На ум тут пришло следующее решение:

__>
__>class CA
__>{
__>    std::unique_ptr<int> m_ui;
__>    //^^^^^^^^^^^^^^^^^^^^^^^
__>    explicit 
__>    CA(const CA& o)
__>        :m_ui(new int(*o.m_ui))
__>    {}
__>    //-----------------------
__>public:
__>    //-----------------------
__>    CA(int i):
__>      m_ui(new int(i))
__>    {}
__>    //-----------------------
__>    CA(CA&&)=default;
__>    //-----------------------
__>    CA clone(){ return CA(*this);}
__>    //-----------------------
__>    int get(){return *m_ui;}
__>    //-----------------------
__>};

__>

__>Но насколько оно соответствует заявленной цели,
По виду не соответсвует, clone != move, у тебя после такого clone сам объект теряет владение над m_ui
__>и может, есть что-нибудь красивее?
Ну, сама идея вроде правильная, пишем operator = в private и в public clone используем, придется да акуратно написать копирование, других вариантов в голову не приходит
__>(И, на всякий случай, есть ограничения — в функции clone нельзя использовать работу с динамической памятью).
С таким ограничением непонятно как это сделать, если только переопределять new и использовать заранее выделеную память
Отредактировано 24.03.2022 6:56 Igore . Предыдущая версия .
Re: Доступ к copy-ctor через отдельный метод
От: Doom100500 Израиль  
Дата: 24.03.22 06:56
Оценка:
Здравствуйте, _hum_, Вы писали:

__>Появилась задача добавить уже существующему классу возможность клонирования его объектов (изначально такой возможности не было — копирование было запрещено). Поскольку класс довольно массивный, то есть опасения, что при написании конструкторов копирования будут ошибки. По этой причине, не хотелось бы открывать эти конструкторы копирования для полного доступа, тем самым открывая возможность их неявного вызова в коде. Хотелось бы, чтобы вызовы конструкторов были только для задачи клонирования, и соответственно, осуществлялись явно. На ум тут пришло следующее решение:

__>
__>class CA
__>{
__>    std::unique_ptr<int> m_ui;
__>    //^^^^^^^^^^^^^^^^^^^^^^^
__>    explicit 
__>    CA(const CA& o)
__>        :m_ui(new int(*o.m_ui))
__>    {}
__>    //-----------------------
__>public:
__>    //-----------------------
__>    CA(int i):
__>      m_ui(new int(i))
__>    {}
__>    //-----------------------
__>    CA(CA&&)=default;
__>    //-----------------------
__>    CA clone(){ return CA(*this);}
__>    //-----------------------
__>    int get(){return *m_ui;}
__>    //-----------------------
__>};

__>

__>Но насколько оно соответствует заявленной цели, и может, есть что-нибудь красивее?
__>(И, на всякий случай, есть ограничения — в функции clone нельзя использовать работу с динамической памятью).

__>Заранее благодарен за советы.


Ну так и делай всё в clone(), зачем тебе обязательно коструктор вызывать от туда?
Спасибо за внимание
Re[2]: Доступ к copy-ctor через отдельный метод
От: _hum_ Беларусь  
Дата: 24.03.22 15:22
Оценка:
Здравствуйте, Igore, Вы писали:

I>Здравствуйте, _hum_, Вы писали:


__>>Появилась задача добавить уже существующему классу возможность клонирования его объектов (изначально такой возможности не было — копирование было запрещено). Поскольку класс довольно массивный, то есть опасения, что при написании конструкторов копирования будут ошибки. По этой причине, не хотелось бы открывать эти конструкторы копирования для полного доступа, тем самым открывая возможность их неявного вызова в коде. Хотелось бы, чтобы вызовы конструкторов были только для задачи клонирования, и соответственно, осуществлялись явно. На ум тут пришло следующее решение:

__>>
__>>class CA
__>>{
__>>    std::unique_ptr<int> m_ui;
__>>    //^^^^^^^^^^^^^^^^^^^^^^^
__>>    explicit 
__>>    CA(const CA& o)
__>>        :m_ui(new int(*o.m_ui))
__>>    {}
__>>    //-----------------------
__>>public:
__>>    //-----------------------
__>>    CA(int i):
__>>      m_ui(new int(i))
__>>    {}
__>>    //-----------------------
__>>    CA(CA&&)=default;
__>>    //-----------------------
__>>    CA clone(){ return CA(*this);}
__>>    //-----------------------
__>>    int get(){return *m_ui;}
__>>    //-----------------------
__>>};

__>>

__>>Но насколько оно соответствует заявленной цели,
I>По виду не соответсвует, clone != move, у тебя после такого clone сам объект теряет владение над m_ui

ммм... я же копию создаю и ее перемещаю, а не исходный объект. Потому ничего он, вроде, не теряет.

__>>и может, есть что-нибудь красивее?

I>Ну, сама идея вроде правильная, пишем operator = в private и в public clone используем, придется да акуратно написать копирование, других вариантов в голову не приходит
__>>(И, на всякий случай, есть ограничения — в функции clone нельзя использовать работу с динамической памятью).
I>С таким ограничением непонятно как это сделать, если только переопределять new и использовать заранее выделеную память

может, как-то можно в clone передавать какой-нибудь пользовательский constructor-allocator, чтоб с его помощью создавать объект и возвращать указатель (чтобы можно было и конструктор перемещения закрыть в private)?
Re[2]: Доступ к copy-ctor через отдельный метод
От: _hum_ Беларусь  
Дата: 24.03.22 15:23
Оценка:
Здравствуйте, Doom100500, Вы писали:

D>Здравствуйте, _hum_, Вы писали:


__>>Появилась задача добавить уже существующему классу возможность клонирования его объектов (изначально такой возможности не было — копирование было запрещено). Поскольку класс довольно массивный, то есть опасения, что при написании конструкторов копирования будут ошибки. По этой причине, не хотелось бы открывать эти конструкторы копирования для полного доступа, тем самым открывая возможность их неявного вызова в коде. Хотелось бы, чтобы вызовы конструкторов были только для задачи клонирования, и соответственно, осуществлялись явно. На ум тут пришло следующее решение:

__>>
__>>class CA
__>>{
__>>    std::unique_ptr<int> m_ui;
__>>    //^^^^^^^^^^^^^^^^^^^^^^^
__>>    explicit 
__>>    CA(const CA& o)
__>>        :m_ui(new int(*o.m_ui))
__>>    {}
__>>    //-----------------------
__>>public:
__>>    //-----------------------
__>>    CA(int i):
__>>      m_ui(new int(i))
__>>    {}
__>>    //-----------------------
__>>    CA(CA&&)=default;
__>>    //-----------------------
__>>    CA clone(){ return CA(*this);}
__>>    //-----------------------
__>>    int get(){return *m_ui;}
__>>    //-----------------------
__>>};

__>>

__>>Но насколько оно соответствует заявленной цели, и может, есть что-нибудь красивее?
__>>(И, на всякий случай, есть ограничения — в функции clone нельзя использовать работу с динамической памятью).

__>>Заранее благодарен за советы.


D>Ну так и делай всё в clone(), зачем тебе обязательно коструктор вызывать от туда?


Не могли бы вы набросать код, о котором говорите?
Re[3]: Доступ к copy-ctor через отдельный метод
От: Igore Россия  
Дата: 25.03.22 07:20
Оценка:
Здравствуйте, _hum_, Вы писали:

__>>>[/ccode]

__>>>Но насколько оно соответствует заявленной цели,
I>>По виду не соответсвует, clone != move, у тебя после такого clone сам объект теряет владение над m_ui
__>ммм... я же копию создаю и ее перемещаю, а не исходный объект. Потому ничего он, вроде, не теряет.
Да, всё верно, я чего то под вечер подумал что CA(CA&&)=default; будет вызываться

__>>>и может, есть что-нибудь красивее?

I>>Ну, сама идея вроде правильная, пишем operator = в private и в public clone используем, придется да акуратно написать копирование, других вариантов в голову не приходит
__>>>(И, на всякий случай, есть ограничения — в функции clone нельзя использовать работу с динамической памятью).
I>>С таким ограничением непонятно как это сделать, если только переопределять new и использовать заранее выделеную память
__>может, как-то можно в clone передавать какой-нибудь пользовательский constructor-allocator, чтоб с его помощью создавать объект и возвращать указатель (чтобы можно было и конструктор перемещения закрыть в private)?
А чем мешает move? Сейчас при clone выполняется выделение памяти, так как объект создается, можно либо использовать память
char *buf  = new char[1000];   //pre-allocated buffer
CA *p = new (buf) CA();  //placement new

либо заранее создать пул объектов выдергивать объект из пула клонировать значения полей, когда он не нужен возвращать в пул
void clone(CA& toClone){ 
   toClone.set( get() );
}

Откуда ограничение что "clone нельзя использовать работу с динамической памятью"?
Re[4]: Доступ к copy-ctor через отдельный метод
От: _hum_ Беларусь  
Дата: 25.03.22 16:06
Оценка:
Здравствуйте, Igore, Вы писали:

I>Здравствуйте, _hum_, Вы писали:


__>>>>[/ccode]

__>>>>Но насколько оно соответствует заявленной цели,
I>>>По виду не соответсвует, clone != move, у тебя после такого clone сам объект теряет владение над m_ui
__>>ммм... я же копию создаю и ее перемещаю, а не исходный объект. Потому ничего он, вроде, не теряет.
I>Да, всё верно, я чего то под вечер подумал что CA(CA&&)=default; будет вызываться

__>>>>и может, есть что-нибудь красивее?

I>>>Ну, сама идея вроде правильная, пишем operator = в private и в public clone используем, придется да акуратно написать копирование, других вариантов в голову не приходит
__>>>>(И, на всякий случай, есть ограничения — в функции clone нельзя использовать работу с динамической памятью).
I>>>С таким ограничением непонятно как это сделать, если только переопределять new и использовать заранее выделеную память
__>>может, как-то можно в clone передавать какой-нибудь пользовательский constructor-allocator, чтоб с его помощью создавать объект и возвращать указатель (чтобы можно было и конструктор перемещения закрыть в private)?
I>А чем мешает move?

ну, хотелось бы полностью запретить неявные вызовы всех конструкторов, включая конструкторы перемещения.

I>либо заранее создать пул объектов выдергивать объект из пула клонировать значения полей, когда он не нужен возвращать в пул

I>
I>void clone(CA& toClone){ 
I>   toClone.set( get() );
I>}
I>

здесь нет создания копии — ваш set предполагает переинициализацию уже созданного. Не всегда такое возможно сделать (например, если класс содержит константное свойство, поменять его с помощью set уже нормально не выйдет)

I>Откуда ограничение что "clone нельзя использовать работу с динамической памятью"?


дело в том, что код состоит из двух частей — первая предназначена для работы на микроконтроллере без динамической памяти, вторая же идет как обвязка для воспроизведения симуляции работы контроллера на ПК. Так вот не хотелось бы эти части смешивать — вносить в первую часть кода все, что связано с динамической памятью.
Re[2]: Доступ к copy-ctor через отдельный метод
От: rg45 СССР  
Дата: 02.04.22 17:02
Оценка: 1 (1)
Здравствуйте, Doom100500, Вы писали:

D>Ну так и делай всё в clone(), зачем тебе обязательно коструктор вызывать от туда?


Во-первых, в классе могут присутствовать члены, которые можно инициализировать только в конструкторе — сслыки, например. Во-вторых, никто не обещал, что у класса доступен конструктор по умолчанию.

Ну у вообще, зачем же конструировать объект по умолчанию, потом тут же его переинициализировать, когда с помощью конструктора копирования можно сразу создать нужный объект.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[5]: Доступ к copy-ctor через отдельный метод
От: rg45 СССР  
Дата: 02.04.22 17:24
Оценка:
Здравствуйте, _hum_, Вы писали:

__>ну, хотелось бы полностью запретить неявные вызовы всех конструкторов, включая конструкторы перемещения.


Конструктор перемещения тоже можно сделать закрытым и это не помешает методу clone работать так, как задумано. Это благодаря наличию Mandatory copy/move elision.

http://coliru.stacked-crooked.com/a/65cde38126b17c3
  Код примера
#include <iostream>
#include <memory>

class CA
{
    std::unique_ptr<int> m_ui;
    //^^^^^^^^^^^^^^^^^^^^^^^
    CA(const CA& o)
        :m_ui(new int(*o.m_ui))
    {}
    //-----------------------
    CA(CA&&)=default;
    //-----------------------

public:
    //-----------------------
    explicit CA(int i):
      m_ui(new int(i))
    {}
    //-----------------------
    CA clone() const { return CA(*this);}
    //-----------------------
    int get(){return *m_ui;}
    //-----------------------
};

int main()
{
    const CA ca1{42};
    const CA ca2 = ca1.clone();
}


Фактически метод clone в этих условиях превращается в абсолютно прозраную прокладку для конструктора копирования. Ровно того же эффекта можно было бы добиться, просто объявив конструкторы копировния и перемещения explicit и оставив их открытыми.

P.S. Метод clone следовало бы объявить константным, а преобразующий конструктор по числу explicit.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 02.04.2022 18:14 rg45 . Предыдущая версия . Еще …
Отредактировано 02.04.2022 18:14 rg45 . Предыдущая версия .
Отредактировано 02.04.2022 18:11 rg45 . Предыдущая версия .
Отредактировано 02.04.2022 17:51 rg45 . Предыдущая версия .
Re: Доступ к copy-ctor через отдельный метод
От: Sm0ke Россия ksi
Дата: 17.04.22 21:15
Оценка:
Здравствуйте, _hum_, Вы писали:

__>Появилась задача добавить уже существующему классу возможность клонирования его объектов (изначально такой возможности не было — копирование было запрещено). Поскольку класс довольно массивный, то есть опасения, что при написании конструкторов копирования будут ошибки. По этой причине, не хотелось бы открывать эти конструкторы копирования для полного доступа, тем самым открывая возможность их неявного вызова в коде. Хотелось бы, чтобы вызовы конструкторов были только для задачи клонирования, и соответственно, осуществлялись явно.


Можно сделать обёртку класс с полем нужного целевого типа. У таргета копи конструктор в приват, а обёртку указываем как friend.
Теперь где надо клонирование — используем обёртку.

https://godbolt.org/z/K4cb31sET

template <typename T>
struct wrap {
    T value;
    wrap(T & src) : value(src) {}
};

class priv_copy {
    friend class wrap<priv_copy>;
    priv_copy(priv_copy const & from) {}
public:
    priv_copy() = default;
};

int main() {
    priv_copy src;
    wrap<priv_copy> dst = src;
    return 0;
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.