6

Suppose there exists a type T such that std::is_trivially_destructable<T>::value == true, and suppose further that T is the value type of some vector class. When the vector's destructor is called, or the vector is assigned to another vector, it must destroy and deallocate its current storage. As T is trivially destructable, is it necessary that I call T's destructor?

Thanks for your help!

void-pointer
  • 14,247
  • 11
  • 43
  • 61
  • 1
    You don't have to call any destructors, the vector will do it for you. – juanchopanza Aug 02 '12 at 15:52
  • Before worrying about the compiler optimizing an empty loop, please look at this example where the result of a recursive function is calculated at compile time. [How does a compiler optimize this factorial function so well?](http://stackoverflow.com/questions/8869189/how-does-a-compiler-optimise-this-factorial-function-so-well) – Bo Persson Aug 02 '12 at 16:19

3 Answers3

8

According to the C++ Standard (section 3.8), you can end an object's lifetime by deallocating or reusing its storage. There's no need to call a destructor that does nothing. On the other hand, letting the compiler optimize away an empty destructor usually results in cleaner and simpler code. Only if you can save substantial additional work, such as iterating through the collection, would you want to special-case trivial destructors.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • Avoiding iteration overhead in the destructor of `vector` is a very good reason to optimize that case. – pmr Aug 02 '12 at 15:58
  • Yeah, this is the use case I had in mind when asking the question. If the compiler's really good, it might be able to optimize `while (l_ != f_) { --l_; l_->~value_type(); }` into `l_ = f_`, but I'd rather rely on type traits. – void-pointer Aug 02 '12 at 16:04
  • 2
    @void-pointer: Enabling that optimization is the whole point of the C++ Standard language requirement (1.10p24) that every thread must either perform a volatile or synchronization operation, I/O, or terminate. The `while` loop isn't allowed to be infinite, and since it has no side effects when there's a trivial destructor, the optimization is formally allowed. Even if the compiler can't prove that iterator decrement ever reaches `f_`. – Ben Voigt Aug 02 '12 at 16:09
  • @void-pointer check your standard library; there's a fair chance that `std::vector` implements precisely your proposed optimisation. – ecatmur Aug 02 '12 at 16:15
  • The exact rule is 3.8.4: You are not obliged to call any destructor. However, if you choose not to call it, any program that depends on the side effects of destruction gets undefined behavior. This can be specificed: since trivial destructors have no side effects, then you can always decide not to call them with no repercussions. – Cort Ammon Sep 06 '13 at 23:16
6

libstdc++ (the standard library the gcc uses by default) applies precisely this optimisation:

  117   /**
  118    * Destroy a range of objects.  If the value_type of the object has
  119    * a trivial destructor, the compiler should optimize all of this
  120    * away, otherwise the objects' destructors must be invoked.
  121    */
  122   template<typename _ForwardIterator>
  123     inline void
  124     _Destroy(_ForwardIterator __first, _ForwardIterator __last)
  125     {
  126       typedef typename iterator_traits<_ForwardIterator>::value_type
  127                        _Value_type;
  128       std::_Destroy_aux<__has_trivial_destructor(_Value_type)>::
  129     __destroy(__first, __last);
  130     }

And the specialisation of std::_Destroy_aux for __has_trivial_destructor(_Value_type) == true:

  109   template<>
  110     struct _Destroy_aux<true>
  111     {
  112       template<typename _ForwardIterator>
  113         static void
  114         __destroy(_ForwardIterator, _ForwardIterator) { }
  115     };

I would expect that most other well-written standard library implementations do the same.

ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • Thanks for the actual source listing! It's good to know that my implementation makes use of this optimization. I actually wanted to know because I was writing a different data structure. – void-pointer Aug 02 '12 at 16:50
1

No, you don't need to call the destructors explicitly. This will be done by the vector's destructor.

Kiril Kirov
  • 37,467
  • 22
  • 115
  • 187