标签: explicit-destructor-call

为什么在析构函数可以不显式调用构造函数?

在下面的C++代码中,我可以显式调用析构函数而不是构造函数.这是为什么?不明确的ctor调用与dtor案件更具表现力统一性吗?

class X { };

int main() {
  X* x = (X*)::operator new(sizeof(X));
  new (x) X;  // option #1: OK
  x->X();     // option #2: ERROR

  x->~X();
  ::operator delete(x);
}
Run Code Online (Sandbox Code Playgroud)

c++ constructor destructor placement-new explicit-destructor-call

28
推荐指数
2
解决办法
3130
查看次数

为什么在std :: move之后需要调用析构函数?

在C++编程语言第4版中,有一个向量实现的示例,请参阅消息末尾的相关代码.

uninitialized_move()通过从旧内存区域移动新T对象将其初始化到新内存区域.然后它调用原始T对象上的析构函数,即移动对象.为什么在这种情况下需要析构函数调用?

这是我的不完全理解:移动对象意味着移动对象拥有的资源的所有权被转移到移动对象.移动对象中的剩余部分是一些不需要销毁的内置类型的可能成员,当vector_base b超出范围时(在reserve ()调用之后,它们将被释放)).移动对象中的所有指针都将被置于nullptr或者使用某种机制来删除这些资源上移动对象的所有权以便我们安全,那么为什么在"vector_base b"时调用耗尽对象上的析构函数"在交换完成后,析构函数仍会解除内存的释放?

我理解在必须调用析构函数时需要显式调用析构函数,因为我们有一些东西需要破坏(例如drop元素)但是在vector_base的std :: move + deallocation之后我看不到它的含义.我在网上阅读了一些文本,我看到被移动对象的析构函数调用作为对象生命周期结束的信号(对谁或什么?).

请告诉我,析构函数还有哪些有意义的工作要做?谢谢!

下面的代码片段来自http://www.stroustrup.com/4th_printing3.html

template<typename T, typename A>
void vector<T,A>::reserve(size_type newalloc)
{
    if (newalloc<=capacity()) return;                   // never decrease allocation
    vector_base<T,A> b {vb.alloc,size(),newalloc-size()};   // get new space
    uninitialized_move(vb.elem,vb.elem+size(),b.elem);  // move elements
    swap(vb,b);                                 // install new base 
} // implicitly release old space

template<typename In, typename Out>
Out uninitialized_move(In b, In e, Out oo)
{
    using T = Value_type<Out>;      // assume suitably defined type function (_tour4.iteratortraits_, _meta.type.traits_) …
Run Code Online (Sandbox Code Playgroud)

c++ memory-management move-semantics c++11 explicit-destructor-call

24
推荐指数
1
解决办法
1万
查看次数

在显式销毁对象之后但在其内存被释放之前调用成员函数是否合法?

我有这个代码:

struct data {
  void doNothing() {}
};

int main() {
    data* ptr = new data();
    ptr->~data();
    ptr->doNothing();
    ::operator delete(ptr);
}
Run Code Online (Sandbox Code Playgroud)

请注意,doNothing()在对象被销毁之后但在其内存被释放之前被调用.看起来"对象生命周期"已经结束,但指针仍然指向正确分配的内存.成员函数不访问任何成员变量.

在这种情况下,成员函数调用是否合法?

c++ destructor object-lifetime language-lawyer explicit-destructor-call

23
推荐指数
2
解决办法
2507
查看次数

显式调用析构函数

我偶然发现了以下代码片段:

#include <iostream>
#include <string>
using namespace std;
class First
{
    string *s;
    public:
    First() { s = new string("Text");}
    ~First() { delete s;}
    void Print(){ cout<<*s;}
};

int main()
{
    First FirstObject;
    FirstObject.Print();
    FirstObject.~First();
}
Run Code Online (Sandbox Code Playgroud)

该文本表示此代码段应该导致运行时错误.现在,我对此并不十分肯定,所以我尝试编译并运行它.有效.奇怪的是,尽管所涉及的数据非常简单,但在打印"文本"之后程序结结巴巴,并且仅在一秒钟之后完成.

我添加了一个要打印到析构函数的字符串,因为我不确定显式调用这样的析构函数是否合法.程序打印两次字符串.所以我的猜测是析构函数被调用两次,因为正常的程序终止不知道显式调用并试图再次销毁对象.

一个简单的搜索确认显式调用自动化对象上的析构函数是危险的,因为第二次调用(当对象超出范围时)具有未定义的行为.所以我很幸运,我的编译器(VS 2017)或这个特定的程序.

关于运行时错误,文本是否完全错误?或者运行时错误真的很常见吗?或者也许我的编译器实现了某种针对这类事情的warding机制?

c++ destructor lifetime undefined-behavior explicit-destructor-call

21
推荐指数
3
解决办法
2223
查看次数

是否允许显式调用析构函数,然后在具有固定生存期的变量上放置new?

我知道显式调用析构函数会因为双析构函数调用而导致未定义的行为,如下所示:

#include <vector>

int main() {
  std::vector<int> foo(10);
  foo.~vector<int>();
  return 0;  // Oops, destructor will be called again on return, double-free.
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我们将新位置称为"复活"对象,该怎么办?

#include <vector>

int main() {
  std::vector<int> foo(10);
  foo.~vector<int>();
  new (&foo) std::vector<int>(5);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

更正式的:

  1. 如果我在某个对象上显式调用析构函数而不是首先使用placement new构造,那么C++中会发生什么(我对C++ 03和C++ 11都感兴趣,如果存在差异)(例如它是本地/全局变量还是被分配了new)然后,在该对象被破坏之前,在其上调用placement new以"恢复"它?
  2. 如果没关系,是否保证对该对象的所有非const引用也都可以,只要我在对象"死"时不使用它们?
  3. 如果是这样,是否可以使用非const引用中的一个用于放置new以恢复对象?
  4. const引用怎么样?

示例用例(虽然这个问题更多是关于好奇心):我想"重新分配"一个没有的对象operator=.

我已经看到这个问题,说"覆盖"具有非静态const成员的对象是非法的.所以,让我们将这个问题的范围限制在没有任何const成员的对象上.

c++ lifetime placement-new c++11 explicit-destructor-call

20
推荐指数
2
解决办法
960
查看次数

伪析构函数调用不会破坏对象

请考虑以下代码:

#include <iostream>

typedef int t;
t a=42;

int main()
{
    a.t::~t();
    std::cout << a; //42
}
Run Code Online (Sandbox Code Playgroud)

我预计a会被摧毁.但事实并非如此,为什么?伪析构函数调用将如何销毁该对象?

c++ destructor primitive-types language-lawyer explicit-destructor-call

11
推荐指数
1
解决办法
1261
查看次数

我们是否需要为"placement new"分配的"简单POD类"显式调用析构函数?

这里的"简单",我指的是一个非虚拟空析构函数或POD类型的类.

典型例子:

char buffer[SIZE];
T *p = new(buffer) T;
...
p->~T();  // <---- always ?
Run Code Online (Sandbox Code Playgroud)

如果我们不调用显式析构函数会发生什么p?我不认为这是未定义的行为或内存泄漏.
重用有什么问题buffer吗?

c++ destructor placement-new explicit-destructor-call

10
推荐指数
2
解决办法
1745
查看次数

我可以使用函数指针调用虚拟析构函数吗?

我有类数据,可以保存指向对象的指针.我希望以后能够手动调用它的析构函数,为此我需要将其地址存储在变量中,但似乎禁止使用构造函数/析构函数的地址.有没有办法解决 ?

struct Data {

  union {
    long i;
    float f;
    void* data_ptr;
  } _data;

  std::type_index _typeIndex;
  void (*_destructor_ptr)();

  template<typename T>
  void Init() {
  if constexpr (std::is_integral<T>::value) {
    //
  }
  else if constexpr (std::is_floating_point<T>::value) {
    //
  }
  else {
    _data.data_ptr = new T;
    _typeIndex = std::type_index(typeid(T));
    _destructor_ptr = &T::~T; // << -- can't do this
  }
}
Run Code Online (Sandbox Code Playgroud)

c++ explicit-destructor-call

10
推荐指数
2
解决办法
688
查看次数

在 C++ 中减少 `constexpr` 对象生命周期是否合法?

对于普通对象(甚至是对象const),允许通过显式调用析构函数来结束它们的生命周期。稍后,例如,程序可以使用放置在同一内存位置启动另一个对象生命周期new

但是调用constexpr对象的析构函数合法吗?它能产生一些有用的或至少是结构良好的程序吗?

很容易想象相反的情况:

struct A{
    int v = 0;
    constexpr void foo() { v ? throw 1 : ++v; }
    constexpr ~A() { foo(); }
};

constexpr A y;

int main() { y.~A(); y.~A(); }
Run Code Online (Sandbox Code Playgroud)

这个(很可能是格式错误的)程序被所有编译器接受,没有任何警告:https : //gcc.godbolt.org/z/aqMbfjxKT

而在锵它完成了从抛出异常constexpr的析构函数A

c++ language-lawyer constexpr explicit-destructor-call

7
推荐指数
1
解决办法
156
查看次数

在'this'指针上使用placement new是否安全

目前的实施

我有一个包含unique_ptr相互依赖的字段的类:

class ResourceManager {
  ResourceManager() {}

  ResourceManager(A* a_ptr) :
    b_ptr(new B(a)),
    c_ptr(new C(b_ptr.get())) {}

  ResourceManager& operator=(ResourceManager&& that) {
    // Call destructor, then construct a new instance on top
    ~ResourceManager();
    ResourceManager* new_this = new(this) ResourceManager();

    // Surely this must be the case, right?
    // Is there any reason to prefer using either?
    assert(new_this == this);

    new_this->b_ptr = that.b_ptr;
    new_this->c_ptr = that.c_ptr;

    return *new_this;
  }

  unique_ptr<B> b;
  unique_ptr<C> c;
};
Run Code Online (Sandbox Code Playgroud)

用例

这里的用例是我想将新值重新分配给指针,同时保持ResourceManager作为堆栈分配的变量,或者作为非指针类成员.

使用我当前的设置,我想像使用这样的东西:

A a, another_a;
ResourceManager …
Run Code Online (Sandbox Code Playgroud)

c++ raii placement-new explicit-destructor-call

6
推荐指数
1
解决办法
549
查看次数