Альтернативный конструктор копирования в С++

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

Было бы полезно скопировать только те переменные-члены, которые мне нужны для моей функции, а не все. Я хотел бы сделать именно это, но я также хотел бы использовать методы в моем скопированном экземпляре.

Вот почему я придумал частный конструктор копирования, который копирует только то, что мне нужно для методов, которые я использую в функции.

Примечание. Я вынужден использовать конструктор, потому что в моем классе есть члены, которые могут быть инициализированы только списком инициализаторов, то есть константными переменными, ссылками, конструкторами базового класса и т.д.

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

#include <ctime>

class MyClass {
public:
    MyClass(const MyClass& other);
    clock_t pure_func() const;
    void messy_method();
private:
    struct ForPureFunc {};
    MyClass(const MyClass& other, ForPureFunc);
};

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

clock_t MyClass::pure_func() const {
    /* 
       lets say I want to time
       the messy method 
    */
    MyClass copy(*this, ForPureFunc());
    clock_t start = clock();
    for (int i = 0; i < 10000; ++i)
        copy.messy_method();
    return clock() - start;
}

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
1
159
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Одно из возможных решений, о котором я подумал, это:

class MyClass {
public:
    MyClass(const MyClass& other);
private:
    class SpecificCopy {
    public:
        SpecificCopy(const MyClass&);
        // only the needed members
    };
    // other members
};

MyClass имеет член типа SpecificCopy?

463035818_is_not_a_number 30.03.2023 18:30

Это не нужно, функция, которая хочет упрощенную копию, имеет объект этого пользовательского типа, инициализированный *this

ugo_capeto 30.03.2023 22:29
Ответ принят как подходящий

Я понимаю, что ваш код просто пример, хотя я не понимаю, для чего. Обратите внимание, что MyClass(const MyClass& other, int) не является конструктором копирования. Конструктор копирования — это MyClass(const MyClass&) не что-то другое. Это различие важно, потому что в большинстве случаев конструктор копирования вызывается неявно, когда вы делаете копию:

 void foo(Example);
 Example a;
 Example b = a; // calls the copy constructor
 foo(b);        // calls the copy constructor

MyClass(const MyClass& other, int) не является конструктором копирования. Если вас это устраивает, то ок. Это просто не конструктор, который будет вызываться неявно при создании копии.

Я знаю, что передача фиктивной переменной — это тот же процесс для перегрузки оператора префикса и постфикса ++:

Использование разрешения перегрузки — хорошая идея. Хотя такого эффекта, как с ++, вы не получите. ++ нужна специальная языковая поддержка, чтобы различать operator++() и operator++(int). Ваш конструктор не может получить эту поддержку.

Я не совсем уверен, хотите ли вы оставить некоторые элементы неинициализированными. Вы не должны этого делать. Лучше пересмотрите свой дизайн. Если MyClass делает больше, чем вам нужно в определенных местах, то это запах дизайна. Очень вероятно, что MyClass делает слишком много для одного класса (см. принцип единой ответственности).

Однако, если вам нужен конструктор, который делает какое-то копирование, доступное только для одной функции, вы можете сделать это:

#include <iostream>

struct MyClass;

void foo(MyClass&);

struct Proxy {
    MyClass& object;
private:
    Proxy(MyClass& object) : object(object) {}
    friend void foo(MyClass&);
};

struct MyClass  {
    MyClass() = default;
    MyClass(const Proxy& p) {} // implement special copy here
    MyClass(const MyClass&) = default; // copy constructor
};

void foo(MyClass& a) {
    MyClass b = Proxy(a);
}

int main() {
    MyClass a;
    MyClass b = Proxy(a); // fails to compile
}

Обратите внимание, что foo получает доступ только к MyClass(const Proxy& p), но не к каким-либо личным частям, которые могут быть у MyClass.

Другие вопросы по теме