LINUX.ORG.RU

error: invalid array assignment

 ,


1

6
int main() {
  int a[10], b[10];
  a = b;
}

https://ideone.com/BdUzkI

prog.cpp: In function ‘int main()’:
prog.cpp:3:7: error: invalid array assignment
   a = b;
       ^

Почему компилятор выдаёт эту ошибку? Стандарт говорит:

http://eel.is/c++draft/expr.ass#1

The assignment operator (=) and the compound assignment operators all group right-to-left. All require a modifiable lvalue as their left operand;

Может, тут не modifiable lvalue? Да вроде нет:

http://eel.is/c++draft/basic.lval#def:modifiable

An lvalue is modifiable unless its type is const-qualified or is a function type.

Так в чём проблема? Почему компилятор выдаёт ошибку, а не делает то, что велит стандарт:

http://eel.is/c++draft/expr.ass#2

In simple assignment (=), the value of the expression replaces that of the object referred to by the left operand.

http://eel.is/c draft/expr.ass#3

If the left operand is not of class type, the expression is implicitly converted ([conv]) to the cv-unqualified type of the left operand.

http://eel.is/c draft/conv#1.1

Zero or one conversion from the following set: lvalue-to-rvalue conversion, array-to-pointer conversion, and function-to-pointer conversion.

http://eel.is/c draft/conv#array-1

An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” can be converted to a prvalue of type “pointer to T”.

Может поэтому?

xaizek ★★★★★
()
Последнее исправление: xaizek (всего исправлений: 1)
Ответ на: комментарий от xaizek

If the left operand is not of class type, the expression is implicitly converted ([conv]) to the cv-unqualified type of the left operand.

Слева int[10], тип совпадает со своей cv-unqualified версие, т.к. никаких квалификаторов нет. Справа тот же тип и конверсия его не поменяет.

An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” can be converted to a prvalue of type “pointer to T”.

«can be converted» != «is always converted». array-to-pointer conversion, как и остальные преобразования, производятся не всегда, а при определённых условиях.

Правая часть оператора присваивания не требует таких преобразований.

sostupid
() автор топика
for (int i = 0; i < 10; ++i) {
    a[i] = b[i];
}

c++draft - это черновик, еще не принятый стандарт? Что это такое?

neon1ks ★★
()
Ответ на: комментарий от neon1ks

c++draft - это черновик, еще не принятый стандарт? Что это такое?

Не понял, это намёк, что цитаты оттуда не катят, а нужны цитаты из Официальной Благословлённой Отцом-Страуструпом Печатной Финальной Версии стандарта, купленной за 200 CHF?

sostupid
() автор топика
Ответ на: комментарий от sostupid

Нет никакого намёка)

Можно обхитрить, хотя думаю можно красивей написать:

#include <iostream>

struct arr {
	int a[10];
};

int main(int argc, char **argv)
{
	arr a, b;
	a=b;
	return 0;
}
neon1ks ★★
()
Ответ на: комментарий от sostupid

А, «the expression» это RHS, так бы и писали. Такое нашёл:

http://eel.is/c draft/dcl.array#7

[ Note: Conversions affecting expressions of array type are described in [conv.array]. Objects of array types cannot be modified, see [basic.lval]. — end note ]

xaizek ★★★★★
()
Последнее исправление: xaizek (всего исправлений: 1)
Ответ на: комментарий от xaizek

А «the expression» это RHS, так бы и писали.

If the left operand is not of class type, the expression is implicitly converted ([conv]) to the cv-unqualified type of the left operand.

Идёт сразу после

In simple assignment (=), the value of the expression replaces that of the object referred to by the left operand.

А тут ясно, что expression это RHS. Видимо, решили, что и в следующем правиле отсюда ясно, что имеется в виду под expression.

Такое нашёл:

Мне такое уже показывали. Проблема в том, что это не правило, а примечание. Примечания (Note), примеры (Example) и подстрочные сноски не являются правилами (требованиями стандарта), а служат для приведения доп. информации.

sostupid
() автор топика
Ответ на: комментарий от xaizek

Может поэтому?

Другого выбора не остаётся. В

In simple assignment (=), the value of the expression replaces that of the object referred to by the left operand.

говорится про value of (RHS) expression, а когда мы в C++ хотим получить значение какого-то выражения, то, как я понимаю, нам нужно, чтобы выражение было prvalue.

А если выражение не prvalue, то производятся неявные преобразования. Способ из lvalue array-типа получить prvalue — это применить

An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” can be converted to a prvalue of type “pointer to T”.

sostupid
() автор топика
Ответ на: комментарий от sostupid

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

ox55ff ★★★★★
()
Ответ на: комментарий от ox55ff

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

Кстати, что бы ты ответил в C++ арифметика указателей: является ли код эквивалентным? ?

sostupid
() автор топика

Может потому, что в данном случае a и b являются константными указателями?

char* const a = nullptr;
char* const b = nullptr;
a = b;

andreyu ★★★★★
()
Ответ на: комментарий от sostupid

int a[10], b[10];
В моём — нет.

Изменить указатель a и b вы не можете. Это константный указатель. В своем топике вы копируете не данные, лежащие по этим указателям, а пытаетесь указателю a присвоить адрес на который указывает b.

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

andreyu ★★★★★
()
Ответ на: комментарий от andreyu

... a и b ... Это константный указатель.

Давайте это проверим. Например, для a, т.к. для b всё будет эквивалентно.

#include <type_traits>
#include <iostream>

int main()
{
  int a[10];
  
  std::cout << std::boolalpha;
  
  std::cout << "Is it a const-qualified type? " << std::is_const_v<decltype(a)> << '\n';
  std::cout << "Is it a pointer type? " << std::is_pointer_v<decltype(a)> << '\n';
}

Вывод (https://wandbox.org/permlink/wvp4tgxraseJlrkP):

Is it a const-qualified type? false
Is it a pointer type? false

Т.е. тип у a не является ни константным, ни указателем.

Дальше сообщение можно не читать, т.к. вывод из неверных посылок доверия заведомо не внушает.

sostupid
() автор топика
Ответ на: комментарий от sostupid

Т.е. тип у a не является ни константным, ни указателем.

И константный, и указатель.

Дальше сообщение можно не читать, т.к. вывод из неверных посылок доверия заведомо не внушает.

Дело ваше, но в топике вы пытаетесь присвоить указателю адрес другого указателя, а не скопировать данные.

andreyu ★★★★★
()
Ответ на: комментарий от andreyu

И константный, и указатель.

Пруф?

в топике вы пытаетесь присвоить указателю адрес другого указателя

Опять мерещится, как с volatile.

sostupid
() автор топика
Ответ на: комментарий от sostupid

Пруф?

Константный потому, что вы его поменять не можете.
Указатель потму, что так говорит Б. Страуструп и на это намекает компилятор - error: invalid array assignment (комментарий)

Опять мерещится, как с volatile.

Может это вам мерещится volatile?

andreyu ★★★★★
()
Ответ на: комментарий от andreyu

Константный потому, что вы его поменять не можете.

Кого — его? Указатель? Указателя никакого нет, см. ещё раз в код с type_traits выше.

Указатель потму, что так говорит Б. Страуструп

Б-г-г. type_traits с ним явно не согласны.

на это намекает компилятор - error: invalid array assignment (комментарий)

Это ты на что-то невнятное намекаешь.

sostupid
() автор топика
Ответ на: комментарий от sostupid

Кого — его? Указатель? Указателя никакого нет, см. ещё раз в код с type_traits выше.

#include <iostream>
int main()
{
    int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    std::cout << std::boolalpha;

    std::cout << "is equal? " << (a[0] == *a) << std::endl;
    std::cout << "is equal? " << (a[5] == *(a + 5)) << std::endl;
    std::cout << "is equal? " << (a[0] == *(a + 5)) << std::endl;

    return 0;
}


is equal? true
is equal? true
is equal? false


Это ты на что-то невнятное намекаешь.

Если сигнатура для вас является невнятным понятием, то я бессилен вам помочь.

andreyu ★★★★★
()
Ответ на: комментарий от andreyu

код

Рад, что ты знаешь, что E1[E2] эквивалентно *((E1)+(E2)), только, опять же, при чём тут это?

я бессилен вам помочь.

Естественно, т.к. твои представления о C++ на уровне какой-нибудь книжки типа «C++ за 24 часа».

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

sostupid
() автор топика
Ответ на: комментарий от sostupid

Рад, что ты знаешь, что E1[E2] эквивалентно *((E1)+(E2)), только, опять же, при чём тут это?

Пытаюсь донести до вас, что error: invalid array assignment (комментарий)

Естественно, т.к. твои представления о C++ на уровне какой-нибудь книжки типа «C++ за 24 часа».

Вы и есть тот самый внук бабы Ванги?

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

Я дал вам достаточно пояснений.

andreyu ★★★★★
()
Ответ на: комментарий от andreyu

error: invalid array assignment (комментарий)

На колу мочало, начинай сначала.

Ну, давай сначала:

#include <type_traits>
#include <iostream>

int main()
{
  int a[10];
  
  std::cout << std::boolalpha;
  
  std::cout << "Is it a const-qualified type? " << std::is_const_v<decltype(a)> << '\n';
  std::cout << "Is it a pointer type? " << std::is_pointer_v<decltype(a)> << '\n';
}

Вывод:

Is it a const-qualified type? false
Is it a pointer type? false

Теперь твой константный указатель

#include <type_traits>
#include <iostream>

int main()
{
  char* const a = nullptr;
  
  std::cout << std::boolalpha;
  
  std::cout << "Is it a const-qualified type? " << std::is_const_v<decltype(a)> << '\n';
  std::cout << "Is it a pointer type? " << std::is_pointer_v<decltype(a)> << '\n';
}
Вывод:
Is it a const-qualified type? true
Is it a pointer type? true

Теперь тебе понятно, что у меня ни константности, ни указателей, а у тебя есть и то, и другое? Я это сразу сказал.

Вы и есть тот самый внук бабы Ванги?

Зачем тут быть Вангой (или её внуком), свой уровень ты упорно демонстрируешь в каждом сообщении, тебя не пронимают самые очевидные доказательство неверности твоих слов.

Я дал вам достаточно пояснений.

Твоя попытка пояснить началась с неверных посылок. А дальше что ты давал — это пара unrelated кусков кода.

sostupid
() автор топика

Сишный массив - тупой указатель на область памяти с сахаром (потому и возможны всякие 0[«A»]), так что просто используй сиплюсный std::array.

anonymous
()
Ответ на: комментарий от anonymous

Сишный массив - тупой указатель на область памяти с сахаром

Бред полный. Иди читай определение (синтаксического) сахара.

sostupid
() автор топика
Ответ на: комментарий от sostupid

Бред полный. Иди читай определение (синтаксического) сахара.

Ок, а 0[«A»] - это получение элемента из 0 по смещению равного указателю на строку? Или это тупой сахар, который заменяет конструкцию *(a+b)?

anonymous
()
Ответ на: комментарий от anonymous

Или это тупой сахар, который заменяет конструкцию *(a+b)?

Не заменяет. Смотрим в стандарт:

http://eel.is/c++draft/expr.sub#1.sentence-5

The expression E1[E2] is identical (by definition) to *((E1)+(E2)) [ Note: see [expr.unary] and [expr.add] for details of * and + and [dcl.array] for details of arrays. — end note  ] , except that in the case of an array operand, the result is an lvalue if that operand is an lvalue and an xvalue otherwise.

Что касается выражения *(a+b):

http://eel.is/c++draft/expr.unary#def:indirection

The unary * operator performs indirection: the expression to which it is applied shall be a pointer to an object type, or a pointer to a function type and the result is an lvalue referring to the object or function to which the expression points. If the type of the expression is “pointer to T”, the type of the result is “T”.

Т.е. тупо синтаксически заменить одно на другое нельзя, будешь терять xvalue-ность.

sostupid
() автор топика
Ответ на: комментарий от anonymous

Cамое главное: ты начал про то, что массивы это сахар, а в следующем сообщении (на которое я отвечаю) ты начал говорить про оператор [].

Давай-ка вернёмся к теме именно массивов. На какую синтаксическую конструкцию языка C++ заменить создание массива внутри функции так, чтобы, например, сторадж под был элементами массива был автоматическим (короче, говоря языком типичной реализации, чтобы память выделилась на стеке)?

sostupid
() автор топика
7 мая 2018 г.
Ответ на: комментарий от anonymous

[ Note: Conversions affecting expressions of array type are described in [conv.array]. — end note ]

Хм. Это p0332R2 Relaxed Incomplete Multidimensional Array Type Declaration приняли? Хоть я там и не нахожу про присваивание, но более близких proposal я тоже не нашёл. И значит ли это, что массивы можно будет присваивать в С++20?

xaizek ★★★★★
()
Ответ на: комментарий от xaizek

Это не proposal приняли, это был обычный editorial fix (fix, который не влияет на трактовку стандарта).

Удалённое утверждение было не верно уже на протяжении, наверное, лет 20-ти.

И значит ли это, что массивы можно будет присваивать в С++20?

Не думаю. До этого нельзя было присваивать не из-за этой Note. Это, повторяю, обычный editorial fix, смысл нормативной части стандарта не изменился из-за удаления предложения про немодифицируемость массивов.

anonymous
()
Ответ на: комментарий от anonymous

До этого нельзя было присваивать не из-за этой Note.

Это понятно. Просто note же должны пояснять нормативную часть, я думал её поменяли и note убрали.

xaizek ★★★★★
()
Ответ на: комментарий от xaizek

Соответствующую нормативную часть, скорее всего, выкинули ещё до C++98.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.