Чи "new" в "new int;" вважається оператором?


84

Вираз new int;типу in int * x = new int;є новим виразом . Термін "новий оператор", схоже, використовується як взаємозамінний із "новим виразом", наприклад у цьому питанні: Різниця між "новим оператором" та "оператором новим"?

Чи правильно говорити, що ключове слово newв новому виразі є оператором? Чому чи чому б ні?

Якщо ні, чи є інше виправдання для виклику нового виразу "новий оператор"?

У мене проблеми з пошуком авторитетного визначення того, що означає оператор.

Я вже розумію різницю між оператором new, який виділяє пам'ять для об'єкта, та "новим виразом", який з часом може викликати an operator new.


4
@Rogue - Річ у тому, newяк sizeofтут. І я думаю, що більшість спільноти C ++ вважає sizeofсебе оператором. Стенсар навіть sizeofописує " оператора" при описі його наслідків.
StoryTeller - Unslander Monica

2
@ StoryTeller-UnslanderMonica, продовжуючи з мого другого коментаря (тепер перенесеного до відповіді) sizeof, я б сказав, що це буде оператором виразу sizeof(<type>). І +є оператором для унарного виразу <type> <op> <type>. Це мій винос / інтерпретація принаймні, не соромтеся виправити мене на цьому.
Rogue

2
@Rogue - Дійсно. Ось чому я б стверджував, що нормативний текст є досить довільним, коли посилається на одного як на оператор, а не на інший.
StoryTeller - Unslander Monica

1
Побічна примітка до прийнятої відповіді: незалежно від того, newє оператором чи ні, існує різниця між виразом та і оператором. Наприклад, new intце вираз, який оцінює щось. Якщо newвважається оператором, тоді оператором є лише "нова" частина new int(тобто це його окрема річ). Концептуально оператор - це те, що діє на щось інше.
Філіп Мілованович

Відповіді:


140

newв new intне вважається оператором. Він також не вважається не оператором.

Стандарт С ++ справді розмитий і навіть суперечливий щодо того, що таке "оператор". Перераховуючи оператори (як визначено під час лексингу та попередньої обробки), він перелічує їх разом із "пунктуаторами" (подібними речами (), але насправді ніколи не дає жодних правил щодо пунктуаторів загалом. Він містить newяк ключове слово, так і оператор. Він входить sizeofдо набору ключових слів, але НЕ до набору операторів, але згодом називає його оператором.

Висновок тут полягає в тому, що комітет зі стандартів С ++ не надто зацікавлений у поділі лексичного світу на "операторів" та "не-операторів". Це тому, що насправді в цьому немає потреби. Немає граматичних правил, які застосовуються до всіх операторів або всіх інших. Важливі набори, як набір операторів, що завантажуються , наводяться окремо; граматичні правила для таких речей, як двійкові арифметичні вирази, подаються по одному.

В основному, "оператор" не є категорією, яка формально має значення для мови С ++, тому будь-яка категорична відповідь буде базуватися на тому, як він "відчуває". Ви можете назвати його оператором, якщо хочете, але можете також назвати ключовим словом (або пунктуацією!), І мовний стандарт не погодиться з вами.


6
Стандарти С і С ++ є неакуратними щодо великої частини їх термінології, оскільки вони очікували, що читачі будуть робити висновки про те, що мається на увазі, якщо є прогалини або неясності, а не намагаються розібратися, чи можуть вони використовувати такі пропуски для виправдання "оптимізації" "у випадках, коли автори Стандардів вважали б достатньо абсурдним, що не було необхідності прямо забороняти їх.
supercat

Стандарт може бути розмитим в описах людей таким чином, але є ключове слово, operatorі я думаю, що коли хтось запитує точне розмежування, справедливо використовувати англійське слово "оператор" для речей, які працюють із цим ключовим словом. У цьому сенсі new, new[], delete, delete[], co_await, деякі приведення типів і перетворення визначається користувача литералов до об'єктів будуть оператори.
hemflit

Оператори @hemflit передують operatorключовому слову та включають такі речі, .які не можна використовувати з цим operatorключовим словом. Якби мене під прицілом зброї змусили придумати визначення поняття "оператор", мій розум не пішов би на "завантажуваний оператор".
Снефтель

Так, використання @Sneftel неоднозначного англійського слова "оператор" передує operatorключовому слову. Якби мене змусили придумати абсолютно точне розмежування того, що є чи ні є оператором, я б погодився з тим, що точно визначено в граматиці. У повсякденному спілкуванні мені не потрібна була б така точність весь час.
hemflit

Я легко визнаю, що це точне визначення. Це просто не добре.
Снефтель

16

Чи правильно говорити, що ключове слово, newяк воно використовується в new-expression, є оператором? Чому чи чому б ні?

Ні . newУ новому експресії є ключовим словом ідентифікації нового самовираження .

Нове вираз викликаєoperator new або operator new[]отримати зберігання. Він також ініціалізує це сховище та видаляє його (за допомогою operator deleteабо operator delete[]), якщо ініціалізація кидає.

Існує чітке розрізнення, яке operator newназивається лише функцією, що може бути замінена користувачем, а новий вираз робить більше, ніж просто викликає цю функцію.

Довідково: 7.6.2.8/10 [expr.new]

Нове вираз може отримати пам'ять для об'єкта шляхом виклику функції розподілу ( [basic.stc.dynamic.allocation]). Якщо новий вираз закінчується, видаючи виняток, він може звільнити пам'ять, викликавши функцію звільнення. Якщо виділений тип є типом, що не є масивом, ім’я функції виділення - це, operator newа функція звільнення - operator delete. Якщо виділений тип є типом масиву, ім’я функції виділення - це, operator new[]а ім’я функції звільнення - operator delete[].


Розглянемо в якості контраприкладу, що ми визначаємо обидва

T operator+(T, T);
void* T::operator new(std::size_t);

для деякого типу Т, то додавання в будь-якій формі:

T a, b;
T c = a + b;
T d = T::operator +(a, b);

є ідентичним. Інфіксне позначення - це просто синтаксичний цукор для дзвінка оператора.

Однак розподіл веде себе по-різному:

T *p = new T;
// does much more than
void *v = T::operator new(sizeof(T));

тому нерозумно називати синтаксичний цукор нового виразу дзвінком до operator new. Таким чином, newключове слово - це не просто вибір функції для виклику. Це не може бути, або потрібно було б згадати operator deleteфункцію, яку також можна викликати.


2
operator newЦе оператор, що завантажується” - чи не так ?! Я не думаю: operator + це не перевантажуваний оператор - +є, і ви визначаєте перевантаження за допомогою функції, що називається operator +.
Конрад Рудольф

1
Ні, я відповів на це, вказавши, що оператор - це специфічна функція, що викликається як частина виразу new. Новий вираз - це вираз, ідентифікований ключовим словом, і він знаходить відповідний оператор для виклику.
Даремно

1
Я все ще не бачу, як це стосується стану newключового слова, як воно відображається в новому виразі.
Джон Боллінгер,

6
Справді, той факт, що newпіддається операційному перевантаженню, наводить на думку, що відповідь повинна бути так , new(сам) є оператором.
Джон Боллінгер,

2
Стандарт стосується лише виразу, який також викликає оператора. Вони не можуть бути одним і тим самим, якщо це не є рекурсивним, тому мізерна інтерпретація полягає в тому, що вираз та оператор є точно і лише тим, що стандарт говорить, що вони є.
Даремно

12

Я хотів би тільки назвати це новим вираз , щоб уникнути плутанини з void* operator new ( std::size_t count )якої тільки виділяє пам'ять як частина процесу в новому вираженні рахунок - фактурі (пам'ять розподілу, починаючи життя, виклик конструктора).

Проблема в newтому, що він робить більше, ніж просто викликати operator new. Який трохи заплутаним , тому що для x + yтих +тільки дзвінки operator +.


9

Це регулюється [expr.new] , який чітко розмежовує новий вираз та те, як новий вираз може отримати пам'ять за допомогою виклику функції виділення , яка має ім'я operator new. Зокрема, з [expr.new] / 8 [ курсив мій]:

Нове вираз може отримати зберігання для об'єкта шляхом виклику функції розподілу ([basic.stc.dynamic.allocation]). Якщо новий вираз закінчується, видаючи виняток, він може звільнити пам'ять, викликавши функцію звільнення. Якщо виділений тип не є масивом, функція виділення має ім'я,operator new а функція звільнення - оператор delete. Якщо виділений тип є типом масиву, ім'я функції виділення є оператором,new[] а ім'я функції звільнення - оператором delete[].


Чи правильно говорити, що ключове слово newв новому виразі є оператором?

Зокрема, приклад, нехай ненормативний, [expr.new] / 4 описує цю функцію як функцію оператора; "[...] newоператор" :

[...] Натомість може бути використана явно в дужках версія нового оператора [...]


3
Дякую за відповідь. Із кількості відповідей, які я отримав, починає здаватися, що, можливо, не існує суворої мови, яка так чи інакше відповідає на це питання. Тож ненормативний текст може виявитись найкращим доказом.
Франсуа Андріє

8

Ні.

Ну, начебто так, в тому сенсі , що існують люди , які вважають newв new intбути оператором. Однак ця думка (в основному) суперечить стандарту.

По-перше, [lex.operators/1]перелічує оператори на мові. Не обманюйте себе, думаючи, що це також просто "оператори попередньої обробки"; не існує такої різниці у значенні лексичних операторів. Це також не мало б сенсу, оскільки ви не можете (наприклад) ++макрос.

newнасправді є ключовим словом (за [lex.key/1]).

Далі, давайте розглянемо сам вираз new . Тут все стає трохи більш шерстяним. Наприклад, є таке формулювання [expr.new/4]:

Натомість версію нового оператора в явних дужках можна використовувати для створення об’єктів складених типів

Вважаю, що це редакційна помилка, оскільки вона суперечить викладеним вище визначенням і більше ніде не зустрічається в цьому розділі.

Тоді ми приходимо до перевантаження оператора . У своєму граматичному створенні для операторської декларації термінал із переліком речей (включаючи new) називається operator ( [over.oper.general/1]). Я не думаю, що нам потрібно турбуватися з цього приводу. Назви терміналів у граматиці ніколи не мали на меті ввести визначення термінів. Зрештою, у вас є і-вираз, що _не потрібно бути побітовою операцією І; це може бути просто вираз рівності :

і-вираз :
   рівність-вираз
   і-вираз & рівність-вираз

Загальноприйнятим є визначення таких граматик, і це, безумовно, не означає, що кожен вираз рівності якось слід вважати викликом побітового оператора І.

Нарешті, деякі стверджували, що наступне формулювання (також у розділі перевантаження оператора) є доказом того, що newзараз якимось чином, ізольовано, магічно є оператором:

Оператори new[], delete[], ()і []утворюються з більш ніж одного маркерів

Для них я кажу, що не тільки newне входить до переліку, але тут явно використовується термін "оператор" у більш широкому розумінні "речі, які можуть бути перевантажені", хоча newсам по собі все ще не є оператором . Це також у ненормативній примітці, яка повинна розповісти вам все, що вам потрібно знати.

І, як ви самі вказуєте, ми вже вважаємо operator newщось інше.


1
[lex.operators] явно неповний (і не має на увазі бути повним!), оскільки [expr.sizeof] нормативно говорить, що sizeofце теж оператор. [expr.throw] є менш явним щодо, throwале він все ще говорить про "операнд" throw, що означає, що throwце оператор.
Конрад Рудольф,

7

Хоча я знаю, що ви шукаєте семантичну відповідь, на мій погляд, я б сказав, що це "ключове слово" (оскільки воно явно зарезервоване), і я припускаю, що ми обоє знаємо, що це просто конструкція C ++ для розподілу пам'яті. Тим не менш, коли я думаю про "оператори" C ++, я схильний думати про функції з набором вводу / виводу, які можна замінити для певних типів. new однаковий для всіх типів (і що більш заплутано його можна замінити).

Не впевнений, наскільки офіційним є cppreference, але:

Новий вираз виділяє пам’ять, викликаючи відповідну функцію розподілу. Якщо тип не є масивом, ім'я функції - оператор new. Якщо type - це тип масиву, ім'я функції - оператор new []

https://en.cppreference.com/w/cpp/language/new

Здається, з цього випливає, що new <type>це вираз для виділення пам'яті, в той час як newє оператором для цього виразу.

Використовуючи ту саму логіку:

  • sizeofє "оператором" для виразу sizeof(<type>)(хоча sizeofце оператор "під час компіляції", дещо відрізняється від того, до чого ми звикли)
  • + є оператором для виразу <type> <operator> <type>
  • throw є оператором для виразу throw <throwaable>

За цією логікою, це []()також оператор? Є for? Є throw?
Конрад Рудольф

1
@KonradRudolph так, я б сказав, []і це ()окремі оператори. Знову ж таки, forце абсолютно ключове слово, але там, де я хотів би визначити оператором, було те, що перша частина можливості була замінена. Технічно цим sizeofне є оператор, що справедливо для С ++, оскільки це більше вираз попередньої обробки. І throwє оператором виразуthrow <throwable>
Rogue

Я спеціально мав []()на увазі поєднання при визначенні лямбда. Але ваша відповідь також цікава, оскільки (на C ++) відповідь залежить від контексту: in foo(), ()є (завантажуваним!) Оператором; в (1 + 2)це не є оператором на всіх (в деяких інших мовах, в зокрема , R, це інше). У будь-якому випадку, критерію, який можна замінити, недостатньо. Є багато речей , в C ++ , які однозначно оператори незважаючи на не перевантажувати ( ., ::, :?, обидва sizeof s, і т.д.).
Конрад Рудольф,

1
Ах, []()як лямбда - це хитрий звір (особливо тому, що я не настільки швидкий на своєму C ++). Отже, тут я все-таки сказав би, що [] ()складають різні оператори лямбда- виразу , але я не впевнений, чи будете ви стверджувати, що їх неможливо замінити, чи сам акт реалізації / оголошення лямбди становить перевагу базової лямбди (як на Java). Мовний дизайн починає перетворюватися на мистецтво над наукою. Наскільки ( ... )це роздільник у більшості мов, якими я користувався, але я швидше розберуся з R
Rogue

2
Як зауваження, у R все є функцією, і все може бути перевизначено. Немає вичерпних нормативних посилань, і я не зовсім впевнений, що дужки вважаються операторами, але їх можна перевизначити; насправді вираз (a + b)семантично ідентичний виклику функції `(` (a + b), або, справді, `(` (`+` (a, b)), де `x` може використовуватися для створення імені xсинтаксично відповідати виклику функції, а не спеціальному (наприклад, оператору інфіксу)
Конрад Рудольф,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.