代码之家  ›  专栏  ›  技术社区  ›  zildjohn01

C++新的操作符问题?

  •  1
  • zildjohn01  · 技术社区  · 17 年前

    我最近遇到过 this rant .

    我不太理解文章中提到的几点:

    • delete delete[] ,但似乎认为它实际上是必要的(对于编译器),但从未提供解决方案。我错过什么了吗?
    • 在“专用分配器”一节中,在函数中 f()

      // if you're going to the trouble to implement an entire Arena for memory,
      // making an arena_ptr won't be much work. basically the same as an auto_ptr,
      // except that it knows which arena to deallocate from when destructed.
      arena_ptr<char> string(a); string.allocate(80);
      // or: arena_ptr<char> string; string.allocate(a, 80);
      arena_ptr<int> intp(a); intp.allocate();
      // or: arena_ptr<int> intp; intp.allocate(a);
      arena_ptr<foo> fp(a); fp.allocate();
      // or: arena_ptr<foo>; fp.allocate(a);
      // use templates in 'arena.allocate(...)' to determine that foo has
      // a constructor which needs to be called. do something similar
      // for destructors in '~arena_ptr()'.
      
    • new(p) obj[10] . 为什么不这样做(更不含糊):

      obj *p = (obj *)special_malloc(sizeof(obj[10]));
      for(int i = 0; i < 10; ++i, ++p)
          new(p) obj;
      
    • “调试C++中的内存分配”。不能在这里争论。

    整篇文章似乎围绕着具有 重要的 位于 自定义内存管理方案 . 虽然这可能是有用的,我也不能否认,但它的公共性相当有限。

    基本上,我们有新的和每类的分配器——这些方法不能解决什么问题?

    还有,万一我只是头盖骨厚而且疯了 理想C++,将取代什么 operator new ? 根据需要发明语法——会是什么 完美的

    2 回复  |  直到 15 年前
        1
  •  5
  •   Charlie Martin    17 年前

    完美的 可能不需要任何形式的删除。有一个垃圾收集的环境,让程序员避免整个问题。

    咆哮中的抱怨似乎归结为

    1. “我喜欢malloc做这件事的方式”
    2. “我不喜欢被迫显式创建已知类型的对象”

    他说得对,令人恼火的是,你必须同时实现这两个目标 new new[]

    *(a+i) == a[i]
    

    这将破坏所有C代码的很大一部分。

    所以,你可以有一种语言

    • 实现了一个更复杂的数组概念,并消除了指针算法的奇迹,实现了带有摄影向量或类似内容的数组。

    • 是垃圾收集的,所以你不需要自己的 delete 纪律

    • 不是强类型,因此请检查 void *

    …但这意味着您可以编写代码,将Foo转换为Bar,而不让编译器看到它。如果您需要,这也将启用ducktyping。

    问题是,一旦你完成了这些事情,你就有了一个C-ish语法的Python或Ruby。

    自从Stroustrup发出CVAX 1的磁带以来,我一直在写C++。C++中涉及的许多历史现在都是出于对一个可以融入C世界的OO语言的渴望。大约在同一时间,还有很多其他更令人满意的语言问世,比如埃菲尔。C++似乎已经赢了。我怀疑它赢了 因为 它可以适应C世界。

        2
  •  3
  •   Richard Corden    17 年前

    这个叫嚣,IMHO,是非常误导的,在我看来,作者确实理解细节,只是他似乎想误导。IMHO,显示参数中缺陷的关键点如下:

    void* operator new(std::size_t size, void* ptr) throw();
    

    本标准规定上述函数具有以下属性:

    笔记 :故意不执行其他操作。

    重申这一点——这一职能 故意不执行其他操作 . 这一点非常重要,因为它是placement new功能的关键:它用于调用对象的构造函数,这就是它的全部功能。请明确注意 大小 甚至没有提到参数。

    明确阐述了他的一些观点:

    要实现多重继承,编译器必须在某些强制转换期间实际更改指针的值。当转换为空*时,它无法知道最终需要哪个值。。。因此,没有一个普通函数可以在C++中执行malloc的角色——没有合适的返回类型。

    这同样是不正确的 ::新操作员 扮演 马洛克 :

    class A1 { };
    class A2 { };
    class B : public A1, public A2 { };
    
    void foo () {
        void * v = ::operator new (sizeof (B));
        B * b = new (v) B();  // Placement new calls the constructor for B.
        delete v;
    
        v = ::operator new (sizeof(int));
        int * i = reinterpret_cast <int*> (v);
        delete v'
    }
    

    正如我上面提到的,我们需要一个新的位置来调用B的构造函数 空虚* 没有问题,尽管再次使用placement new将改进类型检查。

    他提出的另一点是关于对齐要求:

    新字符[…]返回的内存不一定满足struct intlist的对齐要求。

    3.7.3.1/2中的标准规定:

    任何完整对象类型的指针,然后用于访问分配的存储中的对象或数组(直到

    这在我看来很清楚。

    在specialized allocators(专用分配器)下,作者描述了您可能遇到的潜在问题,例如,您需要将分配器用作分配内存的任何类型的参数,并且构造的对象需要显式调用其析构函数。同样,这与将分配器对象传递给C结构的“initalizeMe”调用有何不同?

    关于调用析构函数,C++中可以很容易地创建一种特殊的智能指针,我们称之为“PrimeTyPosiple”,我们可以定义它在析出析构函数时显式调用析构函数。因此,我们可以:

    template <typename T>
    class placement_pointer {
      // ...
      ~placement_pointer() {
        if (*count == 0) {
          m_b->~T();
        }
      }
      // ...
      T * m_b;
    };
    
    void
    f ()
    {
      arena a;
    
      // ...
      foo *fp = new (a) foo;           // must be destroyed
      // ...
      fp->~foo ();
    
      placement_pointer<foo> pfp = new (a) foo; // automatically !!destructed!!
      // ...
    }
    

    我想评论的最后一点是:

    g++附带了一个“placement”操作符new[],定义如下:

    inline void *
    operator new[](size_t, void *place)
    {
      return place;
    }
    

    设obj是一个具有析构函数的类。假设您在某处有sizeof(obj[10])字节的内存,并且希望在该位置构造10个obj类型的对象。(C++将sizeof(obj[10])定义为10*sizeof(obj)。)您可以使用这个放置操作符new[]来实现吗?例如,以下代码似乎就是这样做的:

    obj *
    f ()
    {
      void *p = special_malloc (sizeof (obj[10]));
      return new (p) obj[10];       // Serious trouble...
    }
    

    不幸的是,此代码不正确。一般来说,无法保证传递给运算符new[]的size_t参数确实与所分配数组的大小相对应。

    但正如他通过提供定义所强调的那样,size参数并没有在分配函数中使用。分配功能不起作用 没有什么

    此代码还有其他问题,但不是作者列出的问题。

    推荐文章