4

After update, my Visual Studio compiler started producing "warning C5267: definition of implicit assignment operator for 'Value' is deprecated because it has a user-provided destructor" with the following simple classes defined:

class Value {
public:
  virtual ~Value() = default;
  virtual void print() = 0;
};

class IntValue : public Value {
  int val;
public:
  IntValue(int val_) : val(val_) { }
  virtual void print() override;
};

// class StrValue : public Value { ... }

// Typical usage, what is needed (added on 12/12/2023)
std::vector<std::unique_ptr<Value>> values;
values.emplace_back(std::make_unique<IntValue>(15));

IntValue a, b;
a = b;  // warning
IntValue c(a);  // warning

Documentation refers to Annex D.8 https://eel.is/c++draft/depr.impldec#1 which explains that if there is a "user declared destructor", the generation of "implicit copy assignment" is deprecated. Similarly for implicit copy constructor (https://eel.is/c++draft/class.copy.ctor#6).

Questions: 1. Do I correctly understand that, if I don't want to use deprecated feature, I need to add explicit copy constructor and copy assignment? 2. What to do with move constructor and move assignment? 3. I frequently add virtual destructor to ensure correct destruction through the base class reference. Does it really mean that I generally need to add all these functions below in this case?

class Value {
public:
  virtual ~Value() = default;

  Value(Value const &) = default;  // implicit decl deprecated because of destructor
  Value(Value &&) = default;  // need to add if I need optimized move (if Value had "big attributes)?
  Value &operator=(Value const &) = default;  // implicit decl deprecated becase of destructor
  Value &operator=(Value &&) = default;  // dtto - needed for optimized move assign?
  Value() = default;  // implicit default constr disabled by explicit copy constr above

  virtual void print() = 0;
};

It looks for me as a domino effect and adding just a virtual destructor (which is, per my understanding, quite common) "requires" so much useless code.

12
  • 3
    Now I see it is similar to this question and this answer. If you found something interesting here, you can add, otherwise I close it as a duplicate. Sorry. Commented Dec 11, 2023 at 9:09
  • 1
    Note that for abstract classes you probably want all your constructors and assignment operators to be protected to prevent slicing Commented Dec 11, 2023 at 9:33
  • Also, you don't need a virtual destructor unless you delete a derived class through a pointer to base. In the example here, you never do that. So one option is to remove the unneeded destructor. Commented Dec 11, 2023 at 10:46
  • 1
    I consider it a defect in the standard that these rules key on the relevant special member functions being user-declared (which might just be to add virtual or noexcept or so) rather than user-provided (which indicates special semantics that should disable other defaults). Unfortunately, the move operations were added in terms of user-declared status for everything, so there’s no way to be correct and also consistent (changing the move operations to be generated in more cases would be a very unpleasant breaking change). Commented Dec 12, 2023 at 0:26
  • 1
    @JarekC: virtual ~X()=default; isn’t user-provided, but it is user-declared, and that already causes trouble (for consistency with the unfortunate move-SMF behavior). Commented Dec 13, 2023 at 3:38

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.