คุณ 'realloc' ใน C ++ ได้อย่างไร?


87

ฉันจะreallocอยู่ใน C ++ ได้อย่างไร? ดูเหมือนว่าจะหายไปจากภาษา - มีnewและdeleteแต่ไม่ใช่resize!

ฉันต้องการมันเนื่องจากโปรแกรมของฉันอ่านข้อมูลมากขึ้นฉันจึงต้องจัดสรรบัฟเฟอร์ใหม่เพื่อเก็บไว้ ฉันไม่คิดว่าdeleteการใช้ตัวชี้แบบเก่าและใช้ตัวชี้newใหม่ที่ใหญ่กว่าเป็นตัวเลือกที่เหมาะสม


8
Stroustrup ตอบนี้กลับมานานโปรดดูที่: www2.research.att.com/~bs/bs_faq2.html#renew (นั่นเป็นจุดเริ่มต้นที่ดีถ้าคุณยังใหม่กับ c ++ พร้อมกับไคลน์ c ++ คำถามที่พบบ่อย.)
dirkgently

9
คำตอบอ้างอิงโดย @dirkgently อยู่ที่: stroustrup.com/bs_faq2.html#renew - และตอนนี้คำถามที่พบบ่อยของ Cline เป็นส่วนหนึ่งของคำถามที่พบบ่อยขั้นสูง: isocpp.org/faq
maxschlepzig

คำตอบ:


54

ใช้ :: std :: vector!

Type* t = (Type*)malloc(sizeof(Type)*n) 
memset(t, 0, sizeof(Type)*m)

กลายเป็น

::std::vector<Type> t(n, 0);

แล้ว

t = (Type*)realloc(t, sizeof(Type) * n2);

กลายเป็น

t.resize(n2);

หากคุณต้องการส่งตัวชี้ไปยังฟังก์ชันแทน

Foo(t)

ใช้

Foo(&t[0])

เป็นรหัส C ++ ที่ถูกต้องเนื่องจากเวกเตอร์เป็น C-array ที่ชาญฉลาด


1
ไม่ควรให้บรรทัด memset เป็น memset (t, 0, sizeof (T) * n);? n แทน m?
Raphael Mayer

1
@anthom ใช่. มันควรจะเป็นจริงๆType* t = static_cast<Type*>(malloc(n * sizeof *t));
Ryan Haining

2
ด้วย C ++ 11 ตอนนี้จะใช้t.data()แทน&t[0]
knedlsepp

1
แล้วคุณจะลบสิ่งนี้ได้อย่างไร?
a3mlord

@ a3mlord: คุณหมายถึงอะไร? ปล่อยให้มันอยู่นอกขอบเขตและมันก็หายไป
Lightness Races ใน Orbit

50

std::vectorตัวเลือกที่เหมาะสมน่าจะเป็นที่จะใช้ภาชนะที่ไม่ทำงานให้คุณเช่น

newและdeleteไม่สามารถปรับขนาดได้เนื่องจากจัดสรรหน่วยความจำเพียงพอที่จะเก็บวัตถุประเภทที่กำหนด ขนาดของประเภทที่กำหนดจะไม่เปลี่ยนแปลง มีnew[]และdelete[]แต่แทบจะไม่มีเหตุผลที่จะใช้พวกเขา

สิ่งที่reallocจะอยู่ใน C มีแนวโน้มที่จะเป็นเพียงแค่malloc, memcpyและfreeแล้วแม้ผู้จัดการหน่วยความจำที่ได้รับอนุญาตให้ทำอะไรบางอย่างฉลาดถ้ามีมากพอที่หน่วยความจำฟรีที่ต่อเนื่องกันใช้ได้


6
@bodacydo: อย่าใช้บัฟเฟอร์ที่เพิ่มขึ้นเพียงแค่ใช้std::vector- มันจะเติบโตโดยอัตโนมัติเมื่อจำเป็นและคุณสามารถจัดสรรหน่วยความจำล่วงหน้าได้หากคุณต้องการ ( reserve())
sharptooth

4
ใช้ std :: vector <T> นั่นคือสิ่งที่มีไว้สำหรับ ใน C ++ ไม่มีเหตุผลใด ๆ ที่จะใช้ new / delete / new [] / delete [] ด้วยตัวคุณเองเว้นแต่คุณจะเขียนคลาสการจัดการทรัพยากรอย่างชัดเจน
Puppy

4
@bod: ใช่มันทำได้ (ทำได้std::stringโดยวิธีการ)
fredoverflow

1
ทำได้ไม่มีปัญหา แม้จะstd::stringสามารถทำเช่นนั้น อย่างไรก็ตามมีโอกาสที่การอ่านข้อมูลของคุณจะง่ายขึ้นด้วยเช่นกัน คุณอ่านข้อมูลของคุณอย่างไร
Thomas

2
ดูเหมือนthevector.resize(previous_size + incoming_size)ว่าตามด้วยmemcpy(หรือคล้ายกัน) &thevector[previous_size]เป็นสิ่งที่คุณต้องการ ข้อมูลของเวกเตอร์ได้รับการรับรองว่าจัดเก็บ "เหมือนอาร์เรย์"
Thomas

38

การปรับขนาดใน C ++ เป็นเรื่องที่ไม่สะดวกเนื่องจากอาจต้องเรียกตัวสร้างและตัวทำลาย

ฉันไม่คิดว่ามีเหตุผลพื้นฐานว่าทำไมใน C ++ คุณไม่มีตัวresize[]ดำเนินการที่จะไปด้วยnew[]และdelete[]นั่นก็ทำสิ่งที่คล้ายกับสิ่งนี้:

newbuf = new Type[newsize];
std::copy_n(oldbuf, std::min(oldsize, newsize), newbuf);
delete[] oldbuf;
return newbuf;

เห็นได้ชัดว่าoldsizeจะถูกดึงมาจากสถานที่ลับเช่นเดียวกับที่อยู่ในdelete[]และTypeจะมาจากประเภทของตัวถูกดำเนินการ resize[]จะล้มเหลวในกรณีที่ไม่สามารถคัดลอก Type ได้ซึ่งถูกต้องเนื่องจากไม่สามารถย้ายวัตถุดังกล่าวได้ สุดท้ายโค้ดด้านบนเริ่มต้นสร้างอ็อบเจ็กต์ก่อนกำหนดซึ่งคุณไม่ต้องการให้เป็นพฤติกรรมจริง

มีการเพิ่มประสิทธิภาพที่เป็นไปได้ที่newsize <= oldsizeจะเรียกตัวทำลายสำหรับอ็อบเจ็กต์ "เลยจุดสิ้นสุด" ของอาร์เรย์ที่สร้างใหม่และไม่ต้องทำอะไรเลย มาตรฐานจะต้องกำหนดว่าจำเป็นต้องมีการเพิ่มประสิทธิภาพนี้หรือไม่ (เช่นเมื่อคุณresize()เป็นเวกเตอร์) อนุญาต แต่ไม่ระบุอนุญาต แต่ขึ้นอยู่กับการนำไปใช้งานหรือห้าม

คำถามที่คุณควรถามตัวเองก็คือ "การให้สิ่งนี้มีประโยชน์จริงvectorหรือไม่เนื่องจากยังทำเช่นนั้นและได้รับการออกแบบมาโดยเฉพาะเพื่อจัดเตรียมคอนเทนเนอร์ที่สามารถปรับขนาดได้ (ของหน่วยความจำที่ต่อเนื่องกัน - ข้อกำหนดนั้นละไว้ใน C ++ 98 แต่ แก้ไขใน C ++ 03) ที่เหมาะสมกว่าอาร์เรย์ด้วยวิธีการทำ C ++? "

ฉันคิดว่าคำตอบนั้นคิดกันอย่างกว้างขวางว่า "ไม่" หากคุณต้องการทำบัฟเฟอร์ที่ปรับขนาดได้ด้วยวิธี C ให้ใช้malloc / free / reallocซึ่งมีอยู่ใน C ++ หากคุณต้องการทำบัฟเฟอร์ที่ปรับขนาดได้ด้วยวิธี C ++ ให้ใช้เวกเตอร์ (หรือdequeถ้าคุณไม่ต้องการพื้นที่จัดเก็บที่ต่อเนื่องกัน) อย่าพยายามผสมทั้งสองโดยใช้new[]สำหรับบัฟเฟอร์ดิบเว้นแต่คุณจะใช้คอนเทนเนอร์แบบเวกเตอร์


0

นี่คือตัวอย่าง std :: move ที่ใช้เวกเตอร์อย่างง่ายด้วย realloc (* 2 ทุกครั้งที่เราถึงขีด จำกัด ) หากมีวิธีที่ดีกว่าสำเนาด้านล่างนี้โปรดแจ้งให้เราทราบ

รวบรวมเป็น:

  g++ -std=c++2a -O2 -Wall -pedantic foo.cpp

รหัส:

#include <iostream>
#include <algorithm>

template<class T> class MyVector {
private:
    T *data;
    size_t maxlen;
    size_t currlen;
public:
    MyVector<T> () : data (nullptr), maxlen(0), currlen(0) { }
    MyVector<T> (int maxlen) : data (new T [maxlen]), maxlen(maxlen), currlen(0) { }

    MyVector<T> (const MyVector& o) {
        std::cout << "copy ctor called" << std::endl;
        data = new T [o.maxlen];
        maxlen = o.maxlen;
        currlen = o.currlen;
        std::copy(o.data, o.data + o.maxlen, data);
    }

    MyVector<T> (const MyVector<T>&& o) {
        std::cout << "move ctor called" << std::endl;
        data = o.data;
        maxlen = o.maxlen;
        currlen = o.currlen;
    }

    void push_back (const T& i) {
        if (currlen >= maxlen) {
            maxlen *= 2;
            auto newdata = new T [maxlen];
            std::copy(data, data + currlen, newdata);
            if (data) {
                delete[] data;
            }
            data = newdata;
        }
        data[currlen++] = i;
    }

    friend std::ostream& operator<<(std::ostream &os, const MyVector<T>& o) {
        auto s = o.data;
        auto e = o.data + o.currlen;;
        while (s < e) {
            os << "[" << *s << "]";
            s++;
        }
        return os;
    }
};

int main() {
    auto c = new MyVector<int>(1);
    c->push_back(10);
    c->push_back(11);
}

-7

ลองอะไรแบบนั้น:

typedef struct Board
{
    string name;
    int size = 0;
};

typedef struct tagRDATA
{
    vector <Board> myBoards(255);

    // Board DataBoard[255];
    int SelectedBoard;

} RUNDATA;

เวกเตอร์จะบ่น นั่นเป็นเหตุผลที่อาร์เรย์ malloc และใหม่ยังคงมีอยู่


12
ไม่นั่นไม่ใช่เหตุผล และฉันไม่เห็นว่าสิ่งนี้ตอบคำถามได้อย่างไร หรือทำไมคุณถึงใช้typedefทุกที่ราวกับว่าคุณกำลังเขียน C.
Lightness Races in Orbit เมื่อ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.