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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.