Метод обмена с константными членами - PullRequest
6 голосов
/ 06 февраля 2010

Я хочу реализовать метод Swap () для моего класса (назовем его A), чтобы сделать оператор copy-and-swap = (). Насколько я знаю, метод swap должен быть реализован путем замены всех членов класса, например:

class A 
{
  public:
    void swap(A& rhv) 
    {
        std::swap(x, rhv.x);
        std::swap(y, rhv.y);
        std::swap(z, rhv.z);
    }
  private:
    int x,y,z;
};

Но что мне делать, если у меня есть постоянный член? Я не могу вызвать std :: swap для этого, поэтому я не могу кодировать A :: Swap ().

РЕДАКТИРОВАТЬ: На самом деле мой класс немного сложнее. Я хочу сериализировать и десериализовать это. Член Const - это фрагмент данных, который не изменится (например, его идентификатор) в этом объекте. Поэтому я подумал написать что-то вроде:

class A
{
  public:
    void Serialize(FILE* file) const
    {
        fwrite(&read_a, 1, sizeof(read_a), file);
    }

    void Deserialize(FILE* file) const
    {
        size_t read_a;
        fread(&read_a, 1, sizeof(read_a), file);
        A tmp(read_a);
        this->Swap(tmp);
    }

 private:
   const size_t a;
};

и назовите этот код:

A a;
FILE* f = fopen(...);
a.Deserialize(f);

Прошу прощения за такую ​​расплывчатую формулировку.

Ответы [ 7 ]

8 голосов
/ 06 февраля 2010

Я думаю, что вам действительно нужно иметь внутреннюю структуру данных, которую можно легко обменивать между объектами. Например:

class A 
{
   private:

     struct A_Data {
       int x;
       int y;
       const int z;

       A_Data(int initial_z) : z(initial_z) {}
    };

    std::auto_ptr<A_Data> p_data;

  public:

     A(int initial_z) : p_data(new A_Data(initial_z)) {}

     void swap(A& rhv) {
        std::swap(p_data, rhv.p_data);
     }
};

При этом значение константы z сохраняется в любом экземпляре внутренних данных объекта A, но вы можете поменять местами внутренние данные двух объектов A (включая значение константы z), не нарушая правильность const.

4 голосов
/ 06 февраля 2010

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

3 голосов
/ 06 февраля 2010

f0b0s, хороший принцип проектирования - сделать ваши объекты неизменными . Это означает, что объект не может измениться после создания. Чтобы «изменить» объект, вы должны скопировать объект и убедиться, что изменили нужные элементы.

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

Надеюсь, это поможет.

1 голос
/ 06 февраля 2010

Я предлагаю вам использовать указатели на экземпляры. Указатели можно менять намного проще, чем данные в class или struct.

Единственный способ поменять константное значение - создать другой объект или clone текущий объект.

Учитывая структуру:

struct My_Struct
{
  const unsigned int ID;
  std::string        name;
  My_Struct(unsigned int new_id)
    : ID(new_id)
  { ; }
};

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

Возможно, вам нужно переосмыслить свой дизайн.

0 голосов
/ 15 мая 2018

ТЛ; др; : Это неопределенное поведение.

Ссылка / причина: CppCon 2017: Скотт Шурр «Тип Punning в C ++ 17: Избегание поведения, определяемого Pun, @ 24m52s + -»

Моя интерпретация, например:

Предположим, вы создаете объект типа T, который имеет несколько const членов. Вы можете передать этот объект как неконстантную ссылку на функцию f(&T), которая управляет им, но вы можете ожидать, что члены const останутся неизменными после вызова. swap можно вызывать в неконстантных ссылках, и это может происходить внутри функции f, нарушая предпосылку const членов для вызывающей стороны.

Каждая часть вашего кода, которая использует swap, должна будет утверждать, что объект типа T, который обменивается, не принадлежит ни к какому контексту, где члены const предполагаются постоянными. Это невозможно автоматически проверить *.

* Я просто предположил, что это невозможно проверить, потому что это похоже на расширение неразрешимости проблемы остановки.

0 голосов
/ 06 февраля 2010

ИМХО, вы должны помнить, чтобы не менять местами члены CONST.

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

0 голосов
/ 06 февраля 2010

Вот почему const_cast был создан.Только помните, что не отрывайте ногу.

Редактировать: Хорошо, я согласен - const_cast не был создан для этой проблемы вообщеЭто может работать с вашим компилятором, но вы не можете рассчитывать на это, и если из ваших ноздрей вылетят демоны, пожалуйста, не вините меня.

...