Может размещение, новое для массивов использоваться портативным способом?

Я не думаю, что реальная разница стала понятной в приведенных выше ответах.

Сначала, чтобы получить правильные слова:

  • Вложенный класс - это класс, который содержится в другом классе на уровне исходного кода.
  • It является статическим, если вы объявляете его со статическим модификатором.
  • Нестатический вложенный класс называется внутренним классом. (Я остаюсь с нестатическим вложенным классом.)

Ответ Мартина прав до сих пор. Тем не менее, актуальным вопросом является: Какова цель объявления статического кластера вложенным или нет?

Вы используете статические вложенные классы, если хотите просто сохранить свои классы вместе, если они принадлежат местно вместе или если вложенные класс используется исключительно в классе. Между статическим вложенным классом и каждым другим классом нет семантической разницы.

Нестатические вложенные классы - это другой зверь. Подобно анонимным внутренним классам, такие вложенные классы фактически закрывают. Это означает, что они захватывают свой окружающий масштаб и их охватывающий экземпляр и делают доступным. Возможно, пример пояснит это. См. Этот заглушка контейнера:

public class Container {
    public class Item{
        Object data;
        public Container getContainer(){
            return Container.this;
        }
        public Item(Object data) {
            super();
            this.data = data;
        }

    }

    public static Item create(Object data){
        // does not compile since no instance of Container is available
        return new Item(data);
    }
    public Item createSubItem(Object data){
        // compiles, since 'this' Container is available
        return new Item(data);
    }
}

В этом случае вы хотите получить ссылку от дочернего элемента в родительский контейнер. Используя нестатический вложенный класс, это работает без какой-либо работы. Вы можете получить доступ к закрывающему экземпляру Container с синтаксисом Container.this.

Более подробные пояснения к хардкору:

Если вы посмотрите на байт-коды Java, которые генерирует компилятор для (нестатического ) вложенный класс может стать еще яснее:

// class version 49.0 (49)
// access flags 33
public class Container$Item {

  // compiled from: Container.java
  // access flags 1
  public INNERCLASS Container$Item Container Item

  // access flags 0
  Object data

  // access flags 4112
  final Container this$0

  // access flags 1
  public getContainer() : Container
   L0
    LINENUMBER 7 L0
    ALOAD 0: this
    GETFIELD Container$Item.this$0 : Container
    ARETURN
   L1
    LOCALVARIABLE this Container$Item L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 1
  public <init>(Container,Object) : void
   L0
    LINENUMBER 12 L0
    ALOAD 0: this
    ALOAD 1
    PUTFIELD Container$Item.this$0 : Container
   L1
    LINENUMBER 10 L1
    ALOAD 0: this
    INVOKESPECIAL Object.<init>() : void
   L2
    LINENUMBER 11 L2
    ALOAD 0: this
    ALOAD 2: data
    PUTFIELD Container$Item.data : Object
    RETURN
   L3
    LOCALVARIABLE this Container$Item L0 L3 0
    LOCALVARIABLE data Object L0 L3 2
    MAXSTACK = 2
    MAXLOCALS = 3
}

Как вы видите, компилятор создает скрытое поле Container this$0. Это устанавливается в конструкторе, который имеет дополнительный параметр типа Container для указания экземпляра-оболочки. Вы не можете увидеть этот параметр в источнике, но компилятор неявно генерирует его для вложенного класса.

Пример Мартина

OuterClass.InnerClass innerObject = outerObject.new InnerClass();

был бы скомпилирован для вызова чего-то вроде (в байтекодах)

new InnerClass(outerObject)

Для полноты:

Анонимный класс - прекрасный пример нестатического вложенного класса, у которого просто нет имени, связанного с ним, и на него нельзя ссылаться позже.

36
задан Coding Mash 1 September 2012 в 23:25
поделиться

7 ответов

Лично я пошел бы с опцией не использования размещения, нового на массиве, и вместо этого использовал бы размещение, новое на каждом объекте в массиве индивидуально. Например:

int main(int argc, char* argv[])
{
  const int NUMELEMENTS=20;

  char *pBuffer = new char[NUMELEMENTS*sizeof(A)];
  A *pA = (A*)pBuffer;

  for(int i = 0; i < NUMELEMENTS; ++i)
  {
    pA[i] = new (pA + i) A();
  }

  printf("Buffer address: %x, Array address: %x\n", pBuffer, pA);

  // dont forget to destroy!
  for(int i = 0; i < NUMELEMENTS; ++i)
  {
    pA[i].~A();
  }    

  delete[] pBuffer;

  return 0;
}

Независимо от метода Вы используете, удостоверьтесь, что Вы вручную уничтожаете каждый из тех объектов в массиве перед удалением pBuffer поскольку Вы могли закончить с утечками;)

Примечание : Я не скомпилировал это, но я думаю, что это должно работать (я нахожусь на машине, которой не установили компилятор C++). Это все еще указывает на точку:) Надеюсь, что это помогает в некотором роде!

<час>

Редактирование:

причина, которую это должно отслеживать число элементов, состоит в том так, чтобы это могло выполнить итерации через них, когда Вы звоните, удаляют на массиве и удостоверяются, что деструкторы называют на каждом из объектов. Если бы это не знает, сколько существует это, не был бы в состоянии сделать это.

26
ответ дан user253751 27 November 2019 в 06:14
поделиться

@Derek

5.3.4, разделите 12 переговоров о распределении массива наверху и, если я не неправильно читаю его, это, кажется, намекает мне, что это допустимо для компилятора для добавления его на размещении, новом также:

Эти издержки могут быть применены во всех новых выражениях массива, включая тех, которые ссылаются на оператор библиотечной функции, новый [] (станд.:: size_t, пусто*) и другие функции выделения размещения. Сумма издержек может варьироваться от одного вызова новых для другого.

Однако я думаю, что VC был единственным компилятором, который дал мне проблему с этим, из него, GCC, Codewarrior и PRODG. Я должен был бы проверить снова, чтобы быть уверенным, все же.

4
ответ дан James Sutherland 27 November 2019 в 06:14
поделиться

Спасибо за ответы. Используя размещение, новое для каждого объекта в массиве, было решение, которое я закончил тем, что использовал, когда я столкнулся с этим (извините, должен был упомянуть это в вопросе). Я просто чувствовал, что, должно быть, было что-то, что я пропускал о выполнении его с размещением, новым []. Как это, кажется, что размещение, новое [], чрезвычайно неприменимо благодаря стандарту, позволяющему компилятор добавить дополнительные неуказанные издержки к массиву. Я не вижу, как Вы могли когда-либо использовать его безопасно и портативно.

я даже не действительно ясен, почему этому нужны дополнительные данные, поскольку Вы не звонили бы, удаляют [] на массиве так или иначе, таким образом, я не полностью вижу, почему это должно знать, сколько объектов находится в нем.

2
ответ дан James Sutherland 27 November 2019 в 06:14
поделиться

@James

я даже не действительно ясен, почему ему нужны дополнительные данные, поскольку Вы не звонили бы, удаляет [] на массиве так или иначе, таким образом, я не полностью вижу, почему он должен знать, сколько объектов находится в нем.

После уделения этого некоторого внимания, я соглашаюсь с Вами. Нет никакой причины, почему новое размещение должно должно быть сохранить число элементов, потому что нет никакого размещения, удаляют. С тех пор нет никакого размещения, удаляют, нет никакой причины размещения, нового для хранения числа элементов.

я также протестировал это с gcc на моем Mac, с помощью класса с деструктором. В моей системе новое размещение было не изменение указателя. Это заставляет меня задаться вопросом, является ли это VC ++ проблема, и могло ли это нарушить стандарт (стандарт конкретно не обращается к этому, насколько я могу найти).

2
ответ дан Derek Park 27 November 2019 в 06:14
поделиться

Размещение, новое само, является портативным, но предположения, которые Вы делаете, о каком оно делает с указанным блоком памяти, не являются портативными. Как какой было сказано прежде, если бы Вы были компилятором и были даны блок памяти, как Вы знали бы, как выделить массив и правильно разрушить каждый элемент, если все, что Вы имели, было указателем? (См., что интерфейс оператора удаляет []).

Редактирование:

И на самом деле существует размещение, удаляют, только это только называют, когда конструктор выдает исключение при выделении массива с размещением, новым [].

, Должен ли новый [] на самом деле отслеживать число элементов так или иначе, что-то, что оставляют до стандарта, который оставляет его до компилятора. К сожалению, в этом случае.

2
ответ дан Tim Cooper 27 November 2019 в 06:14
поделиться

Я думаю, что gcc делает то же самое как MSVC, но конечно это не делает его "портативным".

я думаю, что можно работать вокруг проблемы, когда NUMELEMENTS является действительно постоянным временем компиляции, как так:

typedef A Arr[NUMELEMENTS];

А* p = новое (буферное) Прибытие;

Это должно использовать скалярное новое размещение.

0
ответ дан Yossi Kreinin 27 November 2019 в 06:14
поделиться

Подобный тому, как Вы использовали бы единственный элемент для вычисления размера для одного нового для размещения, используйте массив тех элементов для вычисления размера, требуемого для массива.

при требовании размера для других вычислений, где число элементов не может быть известно, можно использовать sizeof ([1]) и умножиться необходимым количеством элемента.

, например,

char *pBuffer = new char[ sizeof(A[NUMELEMENTS]) ];
A *pA = (A*)pBuffer;

for(int i = 0; i < NUMELEMENTS; ++i)
{
    pA[i] = new (pA + i) A();
}
1
ответ дан Andrew Grant 27 November 2019 в 06:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: