Arrays dynamisch toewijzen in C++

Ik weet hoe ik dynamisch ruimte moet toewijzen aan een array in C. Dit kan als volgt:

L = (int*)malloc(mid*sizeof(int)); 

en het geheugen kan worden vrijgegeven door:

free(L);

Hoe bereik ik het equivalent in C++?

In het bijzonder, hoe gebruik ik de zoekwoorden newen delete[]? Vooral in de context van het maken/vernietigen van een gekoppelde lijstknooppunt, of het maken en vernietigen van een array waarvan de grootte wordt gegeven door een variabele tijdens het compileren?


Antwoord 1, autoriteit 100%

L = new int[mid]; 
delete[] L;

voor arrays (wat je wilt) of

L = new int;   
delete L;

voor afzonderlijke elementen.

Maar het is eenvoudiger om vector te gebruiken of smartpointers te gebruiken, dan hoeft u zich geen zorgen te maken over geheugenbeheer.

std::vector<int> L(mid);

L.data()geeft u toegang tot de int[]arraybuffer en u kunt de vector later L.resize().

auto L = std::make_unique<int[]>(mid);

L.get()geeft je een verwijzing naar de int[]array.


Antwoord 2, autoriteit 33%

De volgende informatie is handig:
Bron: https://www.learncpp.com/cpp- tutorial / 6-9A-dynamisch-toewijzing-arrays /

Initialiseren van dynamisch toegewezen arrays

Als u een dynamisch toegewezen array op 0 wilt initialiseren, is de syntaxis vrij eenvoudig:

int *array = new int[length]();

Voorafgaand aan C++ 11 was er geen gemakkelijke manier om een ​​dynamische array te initialiseren op een niet-nulwaarde (initializerlijsten werkten alleen voor vaste arrays). Dit betekent dat je door de array moest en elementwaarden expliciet wijs.

int *array = new int[5];
array[0] = 9;
array[1] = 7;
array[2] = 5;
array[3] = 3;
array[4] = 1;

Super irritant!

Beginnend met C++ 11, is het nu mogelijk om dynamische arrays te initialiseren met behulp van initializerlijsten!

int fixedArray[5] = { 9, 7, 5, 3, 1 }; // initialize a fixed array in C++03
int *array = new int[5] { 9, 7, 5, 3, 1 }; // initialize a dynamic array in C++11

Merk op dat deze syntaxis geen operator = tussen de reekslengte en de initializerlijst heeft.

Voor consistentie, in C++ 11, kunnen vaste arrays ook worden geïnitialiseerd met behulp van uniforme initialisatie:

int fixedArray[5] { 9, 7, 5, 3, 1 }; // initialize a fixed array in C++11
char fixedArray[14] { "Hello, world!" }; // initialize a fixed array in C++11

One waargenomen, in C++ 11 kunt u geen dynamisch toegewezen charreeks initialiseren van een C-Style-string:

char *array = new char[14] { "Hello, world!" }; // doesn't work in C++11

Als je dit nodig hebt, wijs dan dynamisch een std::string toe (of wijs je char-array toe en strcpy de string erin).

Houd er ook rekening mee dat dynamische arrays moeten worden gedeclareerd met een expliciete lengte:

int fixedArray[] {1, 2, 3}; // okay: implicit array size for fixed arrays
int *dynamicArray1 = new int[] {1, 2, 3}; // not okay: implicit size for dynamic arrays
int *dynamicArray2 = new int[3] {1, 2, 3}; // okay: explicit size for dynamic arrays

Antwoord 3, autoriteit 13%

je wijst geheugen toe met de operator newen laat een aanwijzer los met de operator delete. Merk op dat je normale variabelen niet kunt verwijderen, alleen pointers en arrays kunnen worden verwijderd nadat ze hun taak hebben volbracht.

int * foo;
foo = new int [5];
delete[] foo;

een compleet programma

#include <iostream>
#include <new>
using namespace std;
int main ()
{
  int i,n;
  int * p;
  cout << "How many numbers would you like to type? ";
  cin >> i;
  p= new (nothrow) int[i];
  if (p == nullptr)
    cout << "Error: memory could not be allocated";
  else
  {
    for (n=0; n<i; n++)
    {
      cout << "Enter number: ";
      cin >> p[n];
    }
    cout << "You have entered: ";
    for (n=0; n<i; n++)
      cout << p[n] << ", ";
    delete[] p;
  }
  return 0;
}

resultaat

How many numbers would you like to type? 5
Enter number : 75
Enter number : 436
Enter number : 1067
Enter number : 8
Enter number : 32
You have entered: 75, 436, 1067, 8, 32,

Antwoord 4

In C++ hebben we de methoden om dynamisch geheugen te weken en de toewijzen van dynamische geheugen. De variabelen kunnen dynamisch worden toegewezen door newOperator te gebruiken als,

                    type_name *variable_name = new type_name;

De arrays zijn niets anders dan alleen de verzameling van aangrenzende geheugenlocaties, daarom kunnen we dynamisch arrays toewijzen in C++ als,

                    type_name *array_name = new type_name[SIZE];

En u kunt gewoon deletevoor het vrijgeven van de dynamisch toegewezen ruimte, als volgt,
Voor variabelen,

                    delete variable_name;

voor arrays,

                    delete[] array_name;

Antwoord 5

U moet uiterst voorzichtig zijn bij het gebruik van ruwe pointers met dynamisch geheugen, maar hier is een eenvoudig voorbeeld.

int main() {
    // Normal Pointer To Type
    int* pX = nullptr;
    pX = new int;
    *pX = 3;
    std::cout << *pX << std::endl;
    // Clean Up Memory
    delete pX;
    pX = nullptr;
    // Pointer To Array
    int* pXA = nullptr;
    pXA = new int[10]; // 40 Bytes on 32bit - Not Initialized All Values Have Garbage
    pXA = new int[10](0); // 40 Bytes on 32bit - All Values Initialized To 0.
    // Clean Up Memory To An Array Of Pointers.
    delete [] pXA;
    pXA = nullptr;
    return 0;     
} // main

Om geheugenlekken te voorkomen; bungelende wijzers, te vroeg geheugen wissen enz. Probeer slimme wijzers te gebruiken. Ze zijn er in twee varianten: gedeeld en uniek.

SomeClass.h

#ifndef SOME_CLASS_H
#define SOME_CLASS_H
class SomeClass {
private:
    int m_x;
public:
    SomeClass();
    explicit SomeClass( x = 0 );
    void setX( int x );
    int  getX() const;
private:
    SomeClass( const SomeClass& c ); // Not Implemented - Copy Constructor
    SomeClass& operator=( const SomeClass& c ); Not Implemented - Overloaded Operator=
};  // SomeClass
#endif // SOME_CLASS_H

SomeClass.cpp

#include "SomeClass.h"
// SomeClass() - Default Constructor
SomeClass::SomeClass() :
m_x( x ) {
} // SomeClass
// SomeClass() - Constructor With Default Parameter
SomeClass::SomeClass( int x ) :
m_x( x ) {
} // SomeClass
// setX()
void SomeClass::setX( int x ) {
    m_x = x;
} // setX
// getX()
void SomeClass::getX() const {
    return m_x;
} // getX

Oude manier om dynamisch geheugen te gebruiken

#include <iostream>
#include "SomeClass.h"
int main() {
    // Single Dynamic Pointer
    SomeClass* pSomeClass = nullptr;
    pSomeClass = new SomeClass( 5 );
    std::cout << pSomeClass->getX() << std::endl;
    delete pSomeClass;
    pSomeClass = nullptr;
    // Dynamic Array 
    SomeClass* pSomeClasses = nullptr;
    pSomeClasses = new SomeClasses[5](); // Default Constructor Called
    for ( int i = 0; i < 5; i++ ) {
        pSomeClasses[i]->setX( i * 10 );
        std::cout << pSomeSomeClasses[i]->getX() << std::endl;
    }
    delete[] pSomeClasses;
    pSomeClasses = nullptr;  
    return 0;
} // main

Het probleem hier is te weten wanneer, waar en waarom geheugen moet worden verwijderd; weten wie verantwoordelijk is. Als u het geheugen verwijdert om het te beheren en de gebruiker van uw code of bibliotheek neemt aan dat u dit niet hebt gedaan en zij verwijderen het, dan is er een probleem omdat hetzelfde geheugen twee keer probeert te worden verwijderd. Als je het aan de gebruiker overlaat om het te verwijderen en ze gingen ervan uit dat je dat deed en dat is niet zo, dan heb je een probleem en is er een geheugenlek. Dit is waar het gebruik van slimme aanwijzers van pas komt.

Smart Pointer-versie

#include <iostream>
#include <memory>
#include <vector>
#include "SomeClass.h"
int main() {
    // SHARED POINTERS
    // Shared Pointers Are Used When Different Resources Need To Use The Same Memory Block
    // There Are Different Methods To Create And Initialize Shared Pointers
    auto sp1 = std::make_shared<SomeClass>( 10 );
    std::shared_ptr<SomeClass> sp2( new SomeClass( 15 ) );
    std::shared_ptr<SomeClass> sp3;
    sp3 = std::make_shared<SomeClass>( 20 );
    std::cout << "SP1: " << sp1->getX() << std::endl;
    std::cout << "SP2: " << sp2->getX() << std::endl;
    std::cout << "SP3: " << sp3->getX() << std::endl;
    // Now If you Reach The Return Of Main; These Smart Pointers Will Decrement
    // Their Reference Count & When It Reaches 0; Its Destructor Should Be
    // Called Freeing All Memory. This Is Safe, But Not Guaranteed. You Can
    // Release & Reset The Memory Your Self.
    sp1.reset();  
    sp1 = nullptr;
    sp2.reset();
    sp2 = nullptr;
    sp3.reset();
    sp3 = nullptr;
    // Need An Array Of Objects In Dynamic Memory?
    std::vector<std::shared_ptr<SomeClass>> vSomeClasses;
    vSomeClasses.push_back( std::make_shared<SomeClass>( 2 ) );
    vSomeClasses.push_back( std::make_shared<SomeClass>( 4 ) );
    vSomeClasses.push_back( std::make_shared<SomeClass>( 6 ) );
    std::vector<std::shared_ptr<SomeClass>> vSomeClasses2;    
    vSomeClasses2.push_back( std::shared_ptr<SomeClass>( new SomeClass( 3 ) ) );
    vSomeClasses2.push_back( std::shared_ptr<SomeClass>( new SomeClass( 5 ) ) );
    vSomeClasses2.push_back( std::shared_ptr<SomeClass>( new SomeClass( 7 ) ) );
    // UNIQUE POINTERS
    // Unique Pointers Are Used When Only One Resource Has Sole Ownership.
    // The Syntax Is The Same For Unique Pointers As For Shared Just Replace
    // std::shared_ptr<SomeClass> with std::unique_ptr<SomeClass> &
    // replace std::make_shared<SomeClass> with std::make_unique<SomeClass>
    // As For Release Memory It Is Basically The Same
    // The One Difference With Unique Is That It Has A Release Method Where Shared Does Not.
    auto mp1 = std::make_unique<SomeClass>( 3 );
    mp1.release();
    mp1.reset();
    mp1 = nullptr;
    // Now You Can Also Do This:
    // Create A Unique Pointer To An Array Of 5 Integers
    auto p = make_unique<int[]>( 5 );
    // Initialize The Array
    for ( int i = 0; i < 5; i++ ) {
        p[i] = i;
    }
    return 0;
} // main

Hier zijn referentielinks naar zowel Shared & Unieke aanwijzingen

https://msdn.microsoft.com/en-us/library/ hh279669.aspx

https://msdn.microsoft.com/en-us/library/ hh279676.aspx

Other episodes