我需要在这里显式调用析构函数吗?

时间:2018-08-01 18:36:54

标签: c++ c++11

我有一个类似可选的类型(不能使用可选,因为它是C ++ 17):

template <typename T>
struct maybe {
    maybe()        : valid_(false) {}
    maybe(T value) : valid_(true)  { new (&value_) T(value); }

    // destructor
    ~maybe() {
        if (valid_) {
            value_.~T();
        }
    }

    // move value out of maybe
    operator T&&() && {
        valid_ = false;
        return std::move(value());
    }

    // explicit validity 
    explicit operator bool() const {
        return valid_;
    }

    T& value() {
        if (!valid_) {
            throw std::runtime_error("boom");
        }
        return value_;
    }

private:
    union {
        T value_;
    };
    bool valid_;
};

我很想知道operator T&&是否只是将值移出是不合适的,因为析构函数将不再这样做。似乎我需要将值移到临时目录,销毁我的存储,然后返回。哪种方法正确?

2 个答案:

答案 0 :(得分:3)

否,不需要手动调用析构函数。 Move仅用于调用带有右值引用的重载。如果调用代码对函数结果不执行任何操作,则此操作将无效。即使调用代码确实确实弄乱了该值,也应该将其保持在某个有效(但未指定)状态,并且仍然需要适当地对其进行破坏(而maybe对象被破坏时会发生这种情况)。

答案 1 :(得分:1)

start_indices = find(coord(:,1)==0);  % Is exact equality appropriate here?
end_indices = find(coord(:,1)==1);
to_remove = [];
visited = false(size(coord,1), 1);
for ii=start_indices.'
   % For each point with x=0, see if we can reach any of the points at x=1
   [res, visited] = can_reach(ii, end_indices, G, visited);
   if res
      % For this point we can, remove it!
      to_remove(end+1) = ii;
   end
end

% Iterative function to visit all nodes in a connected component
function [res, visited] = can_reach(start, end_indices, G, visited)
   visited(start) = true;
   if any(start==end_indices)
      % We've reach an end point, stop iterating and return true.
      res = true;
      return;
   end
   next = find(G(start,:));  % find neighbors
   next(visited(next)) = []; % remove visited neighbors
   for ii=next
      [res, visited] = can_reach(ii, end_indices, G, visited);
      if res
         % Yes, we can visit an end point, stop iterating now.
         return
      end
   end
end

您的问题是// move value out of maybe operator T&&() && { valid_ = false; return std::move(value()); } -该行是错误的。

您的类具有不变性,即它包含一个值并且valid_ = false;valid_,或者它不包含值并且truevalid_

您的false违反了此不变式。

选项包括:

operator T&&()&&

// move value out of maybe
operator T&&() && {
    return std::move(value());
}

// move value out of maybe operator T() && { T tmp = std::move(value()); value().~T(); valid_ = false; return tmp; } 使用第一个,第二个也是可能的。

顺便说一句:

std::optional

需要maybe(T value) : valid_(true) { new (&value_) T(value); }

std::move

和其他一些防御措施:

maybe(T value) : valid_(true)  { new (&value_) T(std::move(value)); }

处理maybe(T value) : valid_(true) { ::new ((void*)&value_) T(std::move(value)); } 超载。

接下来,您需要处理抛出的构造函数:

operator new

您应该走得更远

maybe(T value) : maybe()  {
  ::new ((void*)&value_) T(std::move(value));
  valid_ = true;
}

现在我们:

template<class...Args>
void emplace(Args&&...args) {
  if (*this)
    clear();
  ::new( (void*)&value_ ) T( std::forward<Args>(args)... );
  valid_ = true;
}
void clear() {
  if (*this)
  {
    valid_ = false; // set false first in case ~T throws
    value().~T(); 
  }
}

,并且只能在maybe(T value) : maybe() { emplace( std::move(value ) ); } ~maybe() { clear(); } value_内手动调整valid_emplace()的生存期。

我们还应该具有有效的clear()值:

noexcept

现在我们:

template<class...Args>
void emplace(Args&&...args)
  noexcept(
    noexcept( T( std::forward<Args>(args)... )
    && noexcept( std::declval<maybe&>().clear() )
 )
{
  if (*this)
    clear();
  ::new( (void*)&value_ ) T( std::forward<Args>(args)... );
  valid_ = true;
}
void clear() noexcept(noexcept( std::declval<T&>().~T() ) ) {
  if (*this)
  {
    valid_ = false; // set false first in case ~T throws
    value().~T(); 
  }
}