Создание массива объектов с использованием нового и вызова конструктора с параметрами [duplicate]

Поведение, которое вы описываете для pull --all, точно так, как ожидалось, хотя и не обязательно полезно. Опция передается по git fetch, которая затем извлекает все ссылки из всех пультов, а не только необходимые; pull затем объединяет (или в вашем случае, переустанавливает) соответствующую отдельную ветвь.

Если вы хотите проверить другие ветви, вам придется проверить их. И да, для слияния (и rebasing) абсолютно требуется дерево работы, поэтому они не могут быть выполнены без проверки других ветвей. Вы можете завершить свои описанные шаги в сценарий / псевдоним, если хотите, хотя я бы предложил присоединиться к командам с &&, чтобы один из них потерпел неудачу, он не будет пытаться вспахивать.

49
задан emlai 22 October 2015 в 14:53
поделиться

11 ответов

Нет.

Но вот! Если вы используете std::vector<Car>, как и должно быть (никогда не используйте new[]), вы можете точно указать, как должны быть построены элементы *.

* Хорошо. Вы можете указать значение для создания копий.


Как это:

#include <iostream>
#include <vector>

class Car
{
private:
    Car(); // if you don't use it, you can just declare it to make it private
    int _no;
public:
    Car(int no) :
    _no(no)
    {
        // use an initialization list to initialize members,
        // not the constructor body to assign them
    }

    void printNo()
    {
        // use whitespace, itmakesthingseasiertoread
        std::cout << _no << std::endl;
    }
};

int main()
{
    int userInput = 10;

    // first method: userInput copies of Car(5)
    std::vector<Car> mycars(userInput, Car(5)); 

    // second method:
    std::vector<Car> mycars; // empty
    mycars.reserve(userInput); // optional: reserve the memory upfront

    for (int i = 0; i < userInput; ++i)
        mycars.push_back(Car(i)); // ith element is a copy of this

    // return 0 is implicit on main's with no return statement,
    // useful for snippets and short code samples
} 

С дополнительной функцией:

void printCarNumbers(Car *cars, int length)
{
    for(int i = 0; i < length; i++) // whitespace! :)
         std::cout << cars[i].printNo();
}

int main()
{
    // ...

    printCarNumbers(&mycars[0], mycars.size());
} 

Примечание printCarNumbers действительно должно быть спроектировано по-разному, чтобы принять два итератора, обозначающих диапазон.

34
ответ дан GManNickG 22 August 2018 в 02:21
поделиться
  • 1
    Это фактически делает то, что мне нужно, но использование вектора не является вариантом. Это должен быть Car, потому что у меня есть другой метод, который принимает * Car not std :: vector & lt; Car & gt; – Dan Paradox 21 January 2011 в 03:23
  • 2
    @Dan: вы можете использовать &mycars[0], чтобы получить указатель на базовый массив. Хотя это обычно полезно только для передачи его устаревшему коду, который не использует std::vector, вы должны обновить это требование, если сможете. – GManNickG 21 January 2011 в 03:24
  • 3
    API низкого уровня часто берут буфер, а иногда они должны быть большими (например, передача данных из захватчика кадров). Иногда вы не можете этого избежать, но вы правы в подавляющем большинстве случаев +1 – Ed S. 21 January 2011 в 03:28
  • 4
    @Ed: Действительно. Мое предположение - это требование, которое может измениться, потому что я сомневаюсь, что API действительно нуждается в Car*. Возможно, void*, и это было просто сказано. :) – GManNickG 21 January 2011 в 03:30
  • 5
    Привет, ребята, у нас есть c ++ 11 вместо &mycars[0], давайте используем эквивалент mycars.data(), который является намного более удобочитаемым. – Russell Greene 1 October 2015 в 04:18

Нет, нет. Новое выражение допускает только инициализацию по умолчанию или вообще не инициализацию.

Обходным решением будет выделение необработанного буфера памяти с помощью operator new[], а затем построение объектов в этом буфере с использованием размещения-new с конструктором, отличным от стандартного.

4
ответ дан AnT 22 August 2018 в 02:21
поделиться
  • 1
    Конечно, мы будем использовать std::vector, который делает это. Но +1 для правильности. – GManNickG 21 January 2011 в 03:20
  • 2
    Как распределить необработанную память с помощью оператора new []? Любая ссылка, которая объясняет это? – Dan Paradox 21 January 2011 в 03:27
  • 3
    @Dan Paradox: В ответе Чана есть пример. – AnT 21 January 2011 в 17:28
  • 4
    ITYM, что форма массива нового выражения допускает только инициализацию по умолчанию, A *a = new A(args); в порядке. Также этот ответ может быть обновлен для C ++ 11 – M.M 1 October 2015 в 03:54

Вы можете использовать новое размещение следующим образом:

class Car {
    int _no;
public:
    Car( int no ) :_no( no ) {
    }
};

int main() {
    void* raw_memory = operator new[]( NUM_CARS * sizeof( Car ) );
    Car* ptr = static_cast<Car*>( raw_memory );
    for( int i = 0; i < NUM_CARS; ++i ) {
        new( &ptr[i] )Car( i );
    }
    // destruct in inverse order    
    for( int i = NUM_CARS - 1; i >= 0; --i ) {
        ptr[i].~Car();
    }
    operator delete[]( raw_memory );
    return 0;
}

Ссылка из более эффективного C ++ - Scott Meyers: Пункт 4 - Избегайте бесполезных конструкторов по умолчанию

51
ответ дан Chan 22 August 2018 в 02:21
поделиться
  • 1
    Почему вы разрушаете в обратном порядке? – miniBill 17 June 2012 в 19:57
  • 2
    @miniBill: Потому что он был построен в прямом порядке. Первое, что было построено, должно быть первым делом разрушено. – Thomas Eding 26 June 2012 в 20:41
  • 3
    Как вы можете сделать это решение безопасным? I.e., что, если конструктор Car выдает исключение для некоторого i? Я предполагаю, что нужно поймать исключение, деконструировать все уже построенные автомобили в обратном порядке и реконструировать ... – ingomueller.net 21 February 2014 в 12:26
  • 4
    что произойдет, если я сделаю только delete [] ptr; в конце? – Youda008 18 December 2014 в 21:25
  • 5
    @Sipka Согласно эксперименту на VS 2015, это приведет к бесконечному циклу. – cqdjyy01234 15 September 2015 в 02:27

Хороший вопрос. У меня был тот же вопрос, и я нашел его здесь. Реальный ответ: @ Dan-Paradox, нет стандартного синтаксического способа сделать это. Итак, все эти ответы - это множество альтернатив, чтобы обойти проблему.

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

class MyClass
{
  int x,y,z;
public:
  MyClass(): x(0), y(0), z(0) {}
  MyClass(int _x,int _y,int _z): x(_x), y(_y), z(_z) {} // for single declarations
  void set(int _x,int _y,int _z)
  {
    x=_x;
    y=_y;
    z=_z;
  }
};

Стандартный конструктор инициализации все еще существует, поэтому я все еще могу его инициализировать, t нужно больше одного, но в противном случае у меня есть метод set, который устанавливает все переменные, которые инициализируются в конструкторе. Таким образом, я мог бы сделать что-то вроде этого:

int len=25;
MyClass list = new MyClass[len];
for(int i = 0; i < len; i++)
  list[i].set(1,2,3);

Это прекрасно работает и протекает естественным образом, не делая код запутанным.


Теперь это мой ответ для тех, кто задается вопросом, как объявите массив объектов, которые должны быть инициализированы.

В частности, вы пытаетесь дать массив идентификаторов автомобилей, которые, я полагаю, вы хотите всегда быть уникальными. Вы можете сделать это с помощью моего метода, который я объяснил выше, а затем в цикле for использовать i+1 в качестве аргумента, переданного методу set, но из того, что я прочитал в ваших комментариях, кажется, что вы хотите Иды более внутренне инициированы, так что по умолчанию у каждого автомобиля есть уникальный идентификатор, даже если кто-то использует ваш класс Car.

Если это то, что вы хотите, вы можете использовать статический член:

class Car
{
  static int current_id;
  int id;
public:
  Car(): id(current_id++) {}

  int getId() { return id; }
};
int Car::current_id = 1;

...

int cars=10;
Car* carlist = new Car[cars];

for(int i = 0; i < cars; i++)
  cout<<carlist[i].getId()<<" "; // prints "1 2 3 4 5 6 7 8 9 10"

Таким образом, вам не нужно беспокоиться об инициализации идентификаторов, поскольку они управляются внутри.

4
ответ дан Codesmith 22 August 2018 в 02:21
поделиться
  • 1
    Вы сделали свой класс небезопасным с помощью статического хранилища для счетчика циклов идентификации. Если они только должны быть уникальными в каждой коллекции, имеет смысл использовать локальную переменную для цикла для повышения эффективности. Может быть, нет четкого способа выразить это на C ++, однако, особенно. а не с инкрементом, скрытым внутри конструктора. – Peter Cordes 1 May 2016 в 03:12

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

1
ответ дан Dagang 22 August 2018 в 02:21
поделиться

Вы можете использовать оператор на месте new.

Car* createCars(unsigned number)
{
    if (number == 0 )
        return 0;
    Car* cars = reinterpret_cast<Car*>(new char[sizeof(Car)* number]);
    for(unsigned carId = 0;
        carId != number;
        ++carId)
    {
        new(cars+carId) Car(carId);
    }
    return cars;
}

И определите соответствующий уничтожить, чтобы соответствовать новому, используемому в этом.

0
ответ дан Keith 22 August 2018 в 02:21
поделиться

Вы всегда можете создать массив указателей, указывая на объекты автомобилей, а затем создать объекты в цикле for, как вы хотите, и сохранить их адрес в массиве, например:

#include <iostream>
class Car
{
private:
  Car(){};
  int _no;
public:
  Car(int no)
  {
    _no=no;
  }
  void printNo()
  {
    std::cout<<_no<<std::endl;
  }
};
void printCarNumbers(Car *cars, int length)
{
    for(int i = 0; i<length;i++)
         std::cout<<cars[i].printNo();
}

int main()
{
  int userInput = 10;
  Car **mycars = new Car*[userInput];
  int i;
  for(i=0;i<userInput;i++)
      mycars[i] = new Car(i+1);

примечание новый способ !!!

  printCarNumbers_new(mycars,userInput);


  return 0;
}    

Все, что вам нужно изменить в новом методе, - это обработка автомобилей как указателей, чем статических объектов в параметре и при вызове метода printNo (), например:

void printCarNumbers_new(Car **cars, int length)
{
    for(int i = 0; i<length;i++)
         std::cout<<cars[i]->printNo();
}

на конец main хорош, чтобы удалить всю динамически распределенную память, подобную этой

for(i=0;i<userInput;i++)
  delete mycars[i];      //deleting one obgject
delete[] mycars;         //deleting array of objects

Надеюсь, я помог, ура!

3
ответ дан kondilidisn 22 August 2018 в 02:21
поделиться

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

static Car*  Car::CreateCarArray(int dimensions)

Но почему вы сохраняете один конструктор общедоступным и другим частным?

Но каким-то еще одним способом является объявление публичного конструктора со значением по умолчанию

#define DEFAULT_CAR_INIT 0
Car::Car(int _no=DEFAULT_CAR_INIT);
2
ответ дан Neera 22 August 2018 в 02:21
поделиться
  • 1
    Я сделал его Car () частным, потому что хочу избежать создания экземпляра копии – Dan Paradox 21 January 2011 в 03:20
  • 2
    @Dan: Но это не конструктор копирования. – GManNickG 21 January 2011 в 03:20
  • 3
    @GMan вы правы, но я все равно хочу избежать конструктора по умолчанию. Все автомобили должны иметь идентификатор – Dan Paradox 21 January 2011 в 03:32
  • 4
    @Dan. В этом случае вы можете использовать заводский метод с размерами и списком инициализации. Заводский метод будет отвечать за создание и массив и инициализацию идентификатора для каждого объекта. Функция инициализации также может быть закрытой. – Neera 21 January 2011 в 03:55

Мой путь

Car * cars;

// else were

extern Car * cars;

void main()
{
    // COLORS == id
    cars = new Car[3] {
        Car(BLUE),
            Car(RED),
            Car(GREEN)
    };
}
0
ответ дан pacholik 22 August 2018 в 02:21
поделиться

В C ++ 11 std::vector вы можете создавать элементы на месте с помощью emplace_back :

  std::vector<Car> mycars;

  for (int i = 0; i < userInput; ++i)
  {
      mycars.emplace_back(i + 1); // pass in Car() constructor arguments
  }

Voila!

Автомобиль () никогда не вызывается.

Удаление происходит автоматически, когда mycars выходит за рамки.

3
ответ дан rustyx 22 August 2018 в 02:21
поделиться
  • 1
    Я столкнулся с аналогичной проблемой, как OP, но мой mycars содержит ссылку, поэтому я не могу использовать emplace_back (так как это может потребовать использования оператора присваивания, которого нет, поскольку ссылки являются const ). Итак, вернемся к исходному вопросу OP, нет возможности создать экземпляр каждого из элементов в массиве, не используя конструктор по умолчанию? – mbrandalero 14 March 2018 в 00:11
  • 2
    Почему вам требуется вызов конструктора для массива ссылок – Kapil 23 March 2018 в 11:22

Вы можете создать массив указателей.

Car** mycars = new Car*[userInput];
for (int i=0; i<userInput; i++){
    mycars[i] = new Car(...);
}

...

for (int i=0; i<userInput; i++){
    delete mycars[i];
}
delete [] mycars;

или

Конструктор Car () не обязательно должен быть общедоступным. Добавьте статический метод в ваш класс, который создает массив:

static Car* makeArray(int length){
    return new Car[length];
}
17
ответ дан Squall 22 August 2018 в 02:21
поделиться
  • 1
    Это имеет тенденцию быть более чистым, чем новый вариант размещения, но как насчет кода, который хочет Car *? – miniBill 17 June 2012 в 19:51
  • 2
    Я бы выбрал это как правильный ответ +1 – Jonathan Mee 19 January 2016 в 20:11
Другие вопросы по тегам:

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