Сначала я вижу проблему, состоящую в том, что ваш конструктор по умолчанию и конструктор копирования не инициализируют myGrid. то, что вы делаете в них, создаст дополнительный массив с тем же именем, которое «затеняет» myGrid. вместо этого вы должны сделать:
Grid::Grid(const Grid& g2)
{
size = g2.size;
row = g2.row;
column = g2.column;
num_living = g2.num_living;
myGrid = new char*[row]; // removed "char**" at the start of this line
for(int i = 0; i < row; i++)
myGrid[i] = new char[column];
for(int i1 = 0; i1 < row; i1++)
{
for(int i2 = 0; i2 < column; i2++)
{
//copy(&g2[i1][i2], &g2[i1][i2]+row*column,&myGrid[i1][i2]);
myGrid[i1][i2] = g2.get(i1,i2);
}
}
}
ваш конструктор по умолчанию имеет ту же проблему. но обратите внимание, что вы не можете инициализировать его с помощью фигурных скобок. но вам не нужно иметь конструктор по умолчанию, если вы его не используете.
Давайте начнем с глупого, но наглядного примера:
Object o = 15;
o = "apples";
Ни в коем случае не создается впечатление, что мы просто превратили число 15 в ряд яблок. Мы знаем, что o
- просто указатель. Теперь давайте сделаем это в форме итератора.
int[] nums = { 15, 16, 17 };
foreach (Object o in nums) {
o = "apples";
}
Опять же, это действительно ничего не дает. Или, по крайней мере, он не смог бы ничего не сделать, если бы его компилировали. Конечно, она не вставит нашу строку в массив int - это недопустимо, и мы знаем, что o
в любом случае является просто указателем.
Давайте рассмотрим ваш пример:
foreach (Position Location in Map)
{
//We want to fudge the position to hide the exact coordinates
Location = Location + Random(); //Compiler Error
Plot(Location);
}
Была ли это компилирована , Местоположение
в вашем примере перестает ссылаться на значение в Map
, но затем вы меняете его, ссылаясь на новую позицию
(неявно созданную добавлением оператор). Функционально это Это эквивалентно этому (что компилируется):
foreach (Position Location in Map)
{
//We want to fudge the position to hide the exact coordinates
Position Location2 = Location + Random(); //No more Error
Plot(Location2);
}
Итак, почему Microsoft запрещает вам переназначать указатель, используемый для итерации? Ясность с одной стороны - вы не хотите, чтобы люди, назначенные на это, думали, что они изменили вашу позицию в цикле. Простота реализации для другого: переменная может скрывать некоторую внутреннюю логику, указывающую состояние текущего цикла.
Но, что еще важнее, у вас нет причин, чтобы хотеть назначить его. Он представляет текущий элемент последовательности цикла. Присвоение ему значения нарушает «Принцип единой ответственности» или Закон Керли , если вы следуете Кодовому Ужасу. Переменная должна означать только одно.
почему Microsoft запрещает вам переназначать указатель, используемый для итерации? Ясность с одной стороны - вы не хотите, чтобы люди, назначенные на это, думали, что они изменили вашу позицию в цикле. Простота реализации для другого: переменная может скрывать некоторую внутреннюю логику, указывающую состояние текущего цикла.Но, что еще важнее, у вас нет причин, чтобы хотеть назначить его. Он представляет текущий элемент последовательности цикла. Присвоение ему значения нарушает «Принцип единой ответственности» или Закон Керли , если вы следуете Кодовому Ужасу. Переменная должна означать только одно.
почему Microsoft запрещает вам переназначать указатель, используемый для итерации? Ясность с одной стороны - вы не хотите, чтобы люди, назначенные на это, думали, что они изменили вашу позицию в цикле. Простота реализации для другого: переменная может скрывать некоторую внутреннюю логику, указывающую состояние текущего цикла.Но, что еще важнее, у вас нет причин, чтобы хотеть назначить его. Он представляет текущий элемент последовательности цикла. Присвоение ему значения нарушает «Принцип единой ответственности» или Закон Керли , если вы следуете Кодовому Ужасу. Переменная должна означать только одно.
Переменная может скрывать некоторую внутреннюю логику, указывающую на состояние цикла в процессе.Но, что еще важнее, у вас нет причин, чтобы хотеть назначить его. Он представляет текущий элемент последовательности цикла. Присвоение ему значения нарушает «Принцип единой ответственности» или Закон Керли , если вы следуете Кодовому Ужасу. Переменная должна означать только одно.
Переменная может скрывать некоторую внутреннюю логику, указывающую на состояние цикла в процессе.Но, что еще важнее, у вас нет причин, чтобы хотеть назначить его. Он представляет текущий элемент последовательности цикла. Присвоение ему значения нарушает «Принцип единой ответственности» или Закон Керли , если вы следуете Кодовому Ужасу. Переменная должна означать только одно.
Если бы переменная была изменяемой, это могло бы создать неправильное впечатление. Например:
string[] names = { "Jon", "Holly", "Tom", "Robin", "William" };
foreach (string name in names)
{
name = name + " Skeet";
}
Некоторые люди могут подумать, что это изменит содержимое массива. Достигает немного, но это может быть причиной. Я посмотрю это сегодня в своей аннотированной спецификации ...
Я думаю, что это искусственное ограничение, в действительности нет необходимости делать это , Чтобы доказать это, примите этот код к сведению и возможное решение вашей проблемы. Проблема заключается в выравнивании, но внутренние изменения объектов не представляют проблемы:
using System;
using System.Collections.Generic;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<MyObject> colection =new List<MyObject>{ new MyObject{ id=1, Name="obj1" },
new MyObject{ id=2, Name="obj2"} };
foreach (MyObject b in colection)
{
// b += 3; //Doesn't work
b.Add(3); //Works
}
}
class MyObject
{
public static MyObject operator +(MyObject b1, int b2)
{
return new MyObject { id = b1.id + b2, Name = b1.Name };
}
public void Add(int b2)
{
this.id += b2;
}
public string Name;
public int id;
}
}
}
Я не знал об этом явлении, потому что я всегда модифицировал объекты так, как я описал.
Оператор foreach работает с Enumerable. Что отличается от Enumerable, так это то, что он не знает о коллекции в целом, он почти слепой.
Это означает, что он не знает, что будет дальше, или, действительно, есть что-то до следующего итерационный цикл. Вот почему там вы видите .ToList () много, чтобы люди могли получить счетчик Enumerable.
По какой-то причине, в которой я не уверен, это означает, что вам нужно убедиться, что ваша коллекция не меняется, так как вы попробуйте переместить счетчик.
При изменении коллекции изменение может иметь непредсказуемые побочные эффекты. Перечислитель не может знать, как правильно справляться с этими побочными эффектами, поэтому они сделали коллекции неизменяемыми.
Смотрите также этот вопрос: Как лучше всего изменить список в foreach
Условием работы с объектами IEnumerable является то, что коллекция не должна изменяться, пока вы обращаетесь к ней с помощью Enumerable. Можно предположить, что объект Enumerable является моментальным снимком исходной коллекции. Поэтому, если вы попытаетесь изменить коллекцию при перечислении, она выдаст исключение. Однако извлеченные объекты в Enumeration не являются неизменяемыми вообще.