Могут ли вызовы выделения памяти и конструктора чередоваться с другими операциями, необходимыми для выполнения «нового» выражения? - PullRequest
3 голосов
/ 04 мая 2011

Предположим, у меня есть следующий класс:

 class Sample {
 public:
     Sample( int ) {}
 };

некоторая функция, возвращающая int

int SomeFunction()
{
    return 0;
}

и этот код:

Sample* sample = new Sample( SomeFunction() );

Теперь я ожидаю следующую последовательность:

  • SomeFunction() выполняется, затем
  • ::operator new() выполняется для выделения памяти для объекта, затем
  • class Sample конструктор запускается через выделенную память

Исправлен ли этот порядок или он может быть изменен такой реализацией, которая говорит, что сначала выделяется память, затем вызывается SomeFunction(), затем запускается конструктор? Другими словами, можно ли вызывать функцию operator new() и вызывать конструктор класса с чем-либо?

Ответы [ 5 ]

8 голосов
/ 04 мая 2011

Заказ не указан.[5.3.4] / 21 гласит:

Вызывается ли [оператор new] перед оценкой аргументов конструктора или после оценки аргументов конструктора, но перед входом в конструктор, не определено.Также не определено, оцениваются ли аргументы конструктора, если [operator new] возвращает нулевой указатель или завершается с использованием исключения.

2 голосов
/ 04 мая 2011

Порядок вызовов оператора new и SomeFunction не указан - поэтому он может меняться в зависимости от настроек оптимизации, версии компилятора и т. Д.

Я думаю, что вызов конструктора должен выполняться последним.

1 голос
/ 04 мая 2011

Да, это может быть чередование.

class A
{
public:
    A(int i)
    {
        cout << "constructor" << endl;
    }
    void* operator new(size_t size)
    {
        cout << "new" << endl;
        return malloc(size);
    }
    void operator delete(void*, size_t)
    {
        cout << "delete" << endl;
    }
};

int f()
{
    cout << "f()" << endl;
    return 1;
}

int main()
{
    A* a = new A(f());
}

Output:
new
f()
constructor

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

0 голосов
/ 04 мая 2011

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

void * p = ::operator new (sizeof (SomeFunction));
SomeFunction temp;
SomeFunction* sample = new (p) SomeFunction(temp);
0 голосов
/ 04 мая 2011

На самом деле, я думаю:

  • new используется для выделения сырой памяти
  • SomeFunction () вызывается, возвращая значение X
  • конструкторуназывается, с X в качестве параметра

, но я могу ошибаться.Я бы сказал, что это показывает, что вы не должны беспокоиться о заказе.

...