简体   繁体   中英

how to implement efficient add in C++ templated list class

Suppose we have a templated c++ list class. Yes, vector exists, but the point is to know how to handle this problem.

The Constructor allocates a block of n objects of type T but does not initialize because they are not used yet.

In the add method, we wish to copy in a new object, but using operator = is not possible because operator = would first destroy the existing object, which was never initialized. How does one copy in an object into data[used] ?

#include <string>
template<typename T>
class DynArray {
private:
  int capacity;
  int used;
  T* data;
public:
  DynArray(int initialCap) : capacity(initialCap), used(0), data((T*)new char[sizeof(T)*capacity]) {}
  void add(const T& e) {
    //TODO: if the dynarray is full, grow
    data[used++] = e; //ERROR! Should use copy constructor!!!
  }
};

int main() {
  DynArray<std::string> a(5);
  a.add(std::string("abc"));
}

You should use placement new:

void add(const T& e) {
    //TODO: if the dynarray is full, grow
    new (data + used) T(e);
    used++;
 }

Placement new constructs an object in already allocated memory.

For what you are attempting to do, you need to call T 's copy constructor using placement-new . And don't forget to implement the Rule of 3/5/0 as well:

template<typename T>
class DynArray {
private:
  int capacity;
  int used;
  T* data;

public:
  DynArray(int initialCap = 0) : capacity(0), used(0), data(0) {
    reserve(initialCap);
  }

  DynArray(const DynArray &src) : capacity(0), used(0), data(0) {
    reserve(src.capacity);
    for(int i = 0; i < src.used; ++i) {
      add(src.data[i]);
    }
  }

  // C++11 and higher only...
  DynArray(DynArray &&src) : capacity(src.capacity), used(src.used), data(src.data) {
    src.capacity = src.used = 0;
    src.data = 0;
  }

  ~DynArray() {
    clear();
    delete[] reinterpret_cast<char*>(data);
  }

  DynArray& operator=(const DynArray &rhs) {
    if (&rhs != this) {
      DynArray(rhs).swap(*this);
    }
    return *this;
  }

  // C++11 and higher only...
  DynArray& operator=(DynArray &&rhs) {
    DynArray(std::move(rhs)).swap(*this);
    return *this;
  }

  void swap(DynArray &other) {
    std::swap(data, other.data);
    std::swap(used, other.used);
    std::swap(capacity, other.capacity);
  }

  void clear() {
    resize(0);
  }

  void reserve(int newCap) {
    // TODO: round up newCap to an even block size...
    if (newCap <= capacity) return;
    T *newData = reinterpret_cast<T*>(new char[sizeof(T) * newCap]);
    for(int i = 0; i < used; ++i) {
      new (newData + i) T(data[i]);
    }
    delete[] reinterpret_cast<char*>(data);
    data = newData;
    capacity = newCap;
  }

  void resize(int newSize) {
    if (newSize < 0) newSize = 0;
    if (newSize == used) return;
    if (newSize > used) {
      reserve(newSize);
      for(int i = used; i < newSize; ++i) {
        new (data + i) T();
        ++used;
      }
    }
    else {
      for(int i = used-1; i >= newSize; --i) {
        data[i]->~T();
        --used;
      }
    }
  }

  void add(const T& e) {
    if (used == capacity) {
        reserve(capacity * 1.5);
    }
    new (data + used) T(e);
    ++used;
  }
};

#include <string>

int main() {
  DynArray<std::string> a(5);
  a.add("abc");
}

The DynArray class has a type of T , so you should simply allocate an array of type T with size of initialCap , which is simply

new T[initialCap];

For built-in types, eg int, the elements are left uninitialized.

For others, like string, the default constructor of T is called to initialize the elements.

In the add method, we wish to copy in a new object, but using operator = is not possible because operator = would first destroy the existing object

data[used++] = e; This is perfectly fine. It assigns e to data[used] - calls the assignment operator of the string, and it won't cause any troubles. However, when your array grows, you would need to allocate new arrays with double capacity, copy over the elements, and destroy the old data.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM