LINUX.ORG.RU

Использование placement new

 


0

3

Помогите разобраться с заданием:

В предыдущей версии предполагается, что для типа T определен оператор присваивания или он ему не нужен (например, для примитивных типов он не нужен). При создании шаблонных классов контейнеров (вроде Array и не только) разумно стараться минимизировать требования к типам шаблонных параметров. Поэтому усложним задачу, реализуйте класс Array не полагаясь на то, что для типа T определен оператор присваивания. Hints: используйте placement new и явный вызов деструктора, чтобы создавать и уничтожать объекты, аллоцировать правильно выровненную память можно с помощью new char[N * sizeof(T)], где N - количество элементов массива.

#include <cstddef>

template <typename T>
class Array
{
    // Список операций:
    //
    // Array(size_t size, const T& value = T())
    //   конструктор класса, который создает
    //   Array размера size, заполненный значениями
    //   value типа T. Считайте что у типа T есть
    //   конструктор, который можно вызвать без
    //   без параметров, либо он ему не нужен.
    //
    // Array()
    //   конструктор класса, который можно вызвать
    //   без параметров. Должен создавать пустой
    //   Array.
    //
    // Array(const Array &)
    //   конструктор копирования, который создает
    //   копию параметра. Для типа T оператор
    //   присвивания не определен.
    //
    // ~Array()
    //   деструктор, если он вам необходим.
    //
    // Array& operator=(...)
    //   оператор присваивания.
    //
    // size_t size() const
    //   возвращает размер массива (количество
    //                              элемнтов).
    //
    // T& operator[](size_t)
    // const T& operator[](size_t) const
    //   две версии оператора доступа по индексу.
};

Вот моё решение:

template <typename T>
class Array
{
public:
    explicit Array(size_t size = 0, const T& value = T())
        :size_(size), data(new T[size])
    {
        for (int i=0; i<size; i++)
            data[i] = value;
    }
    //Array():size_(0), data(new T[0]) {}

    Array(const Array &arrayToCopy)
    {
        size_ = arrayToCopy.size();
        data = static_cast<T*>(operator new[] (size_ * sizeof(T)));
        for ( int i = 0; i < size_; ++i)
            data[i] = arrayToCopy[i];
    }
    ~Array()
    {
        for (int i = 0; i < size_; i++)
          {
              data[i].~T();
          }
        operator delete[](data);
    }

    Array& operator=(const Array & right)
    {
        size_=right.size();
        char * buff = new char[size_ * sizeof(T)];
        data = new (buff) T[size_];
        for (int i=0; i< size_; ++i)
            data[i]=right[i];
        return *this;
    }
    size_t size() const
    {
        return size_;
    }
    T& operator[](size_t i)
    {
        return data[i];
    }
    const T& operator[](size_t i) const
    {
        return data[i];
    }
private:
    size_t size_;
    T * data;
};

А вот выхлоп:

Compilation error main.cpp: In instantiation of ‘Array<T>::Array(size_t, const T&) [with T = Trace; size_t = long unsigned int]’: main.cpp:188:23: required from here main.cpp:177:9: error: ‘Trace& Trace::operator=(const Trace&)’ is private main.cpp:114:13: error: within this context main.cpp: In instantiation of ‘Array<T>& Array<T>::operator=(const Array<T>&) [with T = Trace; Array<T> = Array<Trace>]’: main.cpp:192:11: required from here main.cpp:177:9: error: ‘Trace& Trace::operator=(const Trace&)’ is private main.cpp:140:13: error: within this context main.cpp: In instantiation of ‘Array<T>::Array(const Array<T>&) [with T = Trace; Array<T> = Array<Trace>]’: main.cpp:195:28: required from here main.cpp:177:9: error: ‘Trace& Trace::operator=(const Trace&)’ is private main.cpp:123:13: error: within this context

Подскажите где ошибка?

★★

Ответ на: комментарий от E

Мне показалось, что препод хочет memcpy.

Можно пример типа, который корректно копируется с помощью memcpy, но не присваивается?

const86 ★★★★★
()
Ответ на: комментарий от E

Не думаю что тут нужен memcpy. Мне как то нужно положить в созданный массив объекты типа Т у которого нет оператора присваивания. Пока у меня нет вариантов... Гугль тоже ничего интересного по этой теме не выдает.

Pirr ★★
() автор топика
    Array& operator=(const Array & right)
    {
        size_=right.size();
        T* buff = static_cast<T*>(new char[size_ * sizeof(T)]);
        for (int i=0; i< size_; ++i)
            new (buff + i) T(right[i]);
        return *this;
    }

Оно?

kim-roader ★★
()
Ответ на: комментарий от kim-roader

Да, похоже это то, что нужно. Но теперь выдает другую ошибку:

Compilation error main.cpp: In instantiation of ‘Array<T>& Array<T>::operator=(const Array<T>&) [with T = Trace; Array<T> = Array<Trace>]’: main.cpp:191:11: required from here main.cpp:137:62: error: invalid static_cast from type ‘char*’ to type ‘Trace*’ main.cpp: In instantiation of ‘Array<T>::Array(const Array<T>&) [with T = Trace; Array<T> = Array<Trace>]’: main.cpp:194:28: required from here main.cpp:120:62: error: invalid static_cast from type ‘char*’ to type ‘Trace*’

Pirr ★★
() автор топика
Ответ на: комментарий от const86
struct A {
    int i;
    A() {}
private:
    A& operator=(A&){return *this;}
    A(A&){}
};

int main()
{
    A a;
    a.i = 10;
    A b;
    memcpy(&b, &a, sizeof(A));
    std::cout << b.i << std::endl;
    return 0;
}
E ★★★
()
Ответ на: комментарий от Pirr
  • static_cast -> reinterpret_cast
  • Либо два каста, сначала в void*, потом к типу.
  • Везде использовать operator new[] а не new char (он вроде только в одном месте).

Последний вариант предпочтительней и правильней.

xaizek ★★★★★
()
Последнее исправление: xaizek (всего исправлений: 1)
Ответ на: комментарий от Pirr

Ну да, там статик каст не канает. Надо писать либо

        T* buff = static_cast<T*>(operator new[] (size_ * sizeof(T)));

либо

        T* buff = reinterpret_cast<T*>(new char[size_ * sizeof(T)]);

И не забудь заменить свои data[i] = value; в конструкторах.

kim-roader ★★
()
Ответ на: комментарий от xaizek

Спасибо 3 вариант действительно помог. Что самое интересное, я пример с https://ru.wikipedia.org/wiki/New_(C++)#Placement_new засмотрел до дыр, но так и не смог переложить его на свою задачу... но фактическим решением оказался именно этот пример.

Pirr ★★
() автор топика
Ответ на: комментарий от Pirr

Подскажите, если не сложно, как вы сделали предыдущее задание на stepic.org


Вот моё решение:

#include <cstddef>

template <typename T>

class Array
{
public:

    explicit Array(size_t size = 0, const T& value = T())
    {
        size_ = size;
        T *data_ = new T[size];
        for (int i=0; i < size_; i++)
        {
            data_[i] = value;
        }

    }


    Array(const Array &a)
    {
        size_ = a.size();

        T* data_ = new T[size_];

        for (int i=0; i != size_; ++i)
        {
            data_[i] = a[i];  
        }

    }
    
    ~Array()
    {
         delete[] data_;
    }


    Array& operator=(const Array & a)
    {
        size_=a.size();

        for (int i=0; i != size_; ++i)
        {
            data_[i]=a[i];
        }
            
        return *this;
    }
    size_t size() const
    {
        return size_;
    }
    T &operator[](int i)
    {
        return data_[i];
    }
    const T &operator[](int i) const
    {
        return data_[i];
    }
private:
    size_t size_;
    T * data_;
};

Вот output:
Failed test #1. Run time error:

kiramipt
()

Вот решение:

#include <cstddef>

template <typename T>
class Array
{
    public:
    explicit Array(size_t size = 0, const T& value = T())
        :size_(size), data(new T[size])
    {
        for (int i=0; i<size; i++)
            data[i] = value;
    }
    Array(const Array &arrayToCopy)
    {
        size_ = arrayToCopy.size();
        data = new T[size_];
        for ( int i = 0; i < size_; ++i)
            data[i] = arrayToCopy.data[i];
    }
    ~Array()
    {
        delete [] data;
    }
    Array& operator=(const Array & right)
    {
        
            delete [] data;
            size_=right.size();
            data= new T[size_];
        
        for (int i=0; i< size_; ++i)
            data[i]=right.data[i];
        return *this;
    }
    size_t size() const
    {
        return size_;
    }
    T& operator[](size_t i)
    {
        return data[i];
    }
    const T& operator[](size_t i) const
    {
        return data[i];
    }
private:
    size_t size_;
    T * data;
};

Pirr ★★
() автор топика

Как вы и тоге решили эту задачу?

anonymous
()
Ответ на: комментарий от Pirr
/*new (data + i) T();*/
template <typename T>
class Array
{
public:
    explicit Array(size_t size = 0, const T& value = T())
        :size_(size), data(new T[size])
    {
        for (int i=0; i<size; i++)
            new (data + i) T(value);
    }

    Array(const Array &arrayToCopy)
    {
        size_ = arrayToCopy.size();
        data =static_cast<T*>(operator new[] (size_ * sizeof(T)));
        for ( int i = 0; i < size_; ++i)
            new (data + i) T(arrayToCopy[i]);
    }
    ~Array()
    {
        for (int i = 0; i < size_; i++)
          {
              data[i].~T();
          }
        operator delete[](data);
    }

    Array& operator=(const Array & right)
    {
        size_=right.size();
        T* buff = static_cast<T*>(operator new[] (size_ * sizeof(T)));
        for (int i=0; i< size_; ++i)
            new (buff + i) T(right[i]);
        return *this;
    }
    size_t size() const
    {
        return size_;
    }
    T& operator[](size_t i)
    {
        return data[i];
    }
    const T& operator[](size_t i) const
    {
        return data[i];
    }
private:
    size_t size_;
    T * data;
};

вылетает Failed test #1. Чего не так?

general1
()
Ответ на: комментарий от general1

Ты подумай, что ты делаешь в операторе присваивания... прямо проговори все действия и поймешь свою ошибку.

Pirr ★★
() автор топика
Ответ на: комментарий от Pirr

решение

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

anonymous
()
Ответ на: комментарий от Pirr
/*new (data + i) T();*/
template <typename T>
class Array
{
public:
    explicit Array(size_t size = 0, const T& value = T())
        :size_(size), data(new T[size])
    {
        for (int i=0; i<size; i++)
            new (data + i) T(value);
    }

    Array(const Array &arrayToCopy)
    {
        size_ = arrayToCopy.size();
        data =static_cast<T*>(operator new[] (size_ * sizeof(T)));
        for ( int i = 0; i < size_; ++i)
            new (data + i) T(arrayToCopy[i]);
    }
    ~Array()
    {
        for (int i = 0; i < size_; i++)
          {
              data[i].~T();
          }
        operator delete[](data);
    }

    Array& operator=(const Array & right)
    {
        delete [] data;
        size_=right.size();
        T* data = static_cast<T*>(operator new[] (size_ * sizeof(T)));
        for (int i=0; i< size_; ++i)
            new (data + i) T(right[i]);
        return *this;
    }
    size_t size() const
    {
        return size_;
    }
    T& operator[](size_t i)
    {
        return data[i];
    }
    const T& operator[](size_t i) const
    {
        return data[i];
    }
private:
    size_t size_;
    T * data;
};

Все та же ошибка

general1
()
Ответ на: комментарий от Pirr

уважаемый буду очень благодарен если вы опубликуете свое решение, а то самостоятельно разобраться до дедлайна уже совсем надежды нет(

mikemiem
()
Ответ на: комментарий от mikemiem

Ok.

Array& operator=(const Array & right)
    {
        operator delete[](data);
        size_=right.size();
        data = static_cast<T*>(operator new[](size_ * sizeof(T)));
        for (int i=0; i< size_; ++i)
            new (data + i) T(right[i]);
        return *this;
    }

Pirr ★★
() автор топика
Ответ на: комментарий от Pirr

эта часть у меня и так такая) но это не помогает все равно ошибка

mikemiem
()
Ответ на: комментарий от general1

Ну, чтож ловите:

#include <cstddef>

template <typename T>
class Array
{
public:
    explicit Array(size_t size = 0, const T& value = T())
        :size_(size), data(static_cast<T*>(operator new[](size * sizeof(T))))
    {
        for (int i=0; i< size_; ++i)
            new (data + i) T(value);
    }

    Array(const Array &arrayToCopy)
    {
        size_ = arrayToCopy.size();
        data = static_cast<T*>(operator new[](size_ * sizeof(T)));
        for (int i=0; i< size_; ++i)
            new (data + i) T(arrayToCopy[i]);
    }
    ~Array()
    {
        for (int i = 0; i < size_; i++)
          {
              data[i].~T();
          }
        operator delete[](data);
    }


    Array& operator=(const Array & right)
    {
        operator delete[](data);
        size_=right.size();
        data = static_cast<T*>(operator new[](size_ * sizeof(T)));
        for (int i=0; i< size_; ++i)
            new (data + i) T(right[i]);
        return *this;
    }
    size_t size() const
    {
        return size_;
    }
    T& operator[](size_t i)
    {
        return data[i];
    }
    const T& operator[](size_t i) const
    {
        return data[i];
    }
private:
    size_t size_;
    T * data;
};
Pirr ★★
() автор топика
Ответ на: комментарий от general1

мне кажется в присваивание еще должен быть цыкл для удаление,но все равно wrong anser

mikemiem
()
Ответ на: комментарий от general1

Ну значит я своим вариантом замучал тестовую машину. Там какой то нюанс был с delete, у меня похоже не окончательный вариант сохранился.

Pirr ★★
() автор топика
Ответ на: комментарий от Pirr

на степике можно по кнопке решение посмотреть успешный вариант

mikemiem
()
Ответ на: комментарий от general1

#include <iostream>

// Весь вывод должен осущствляться в поток out, // переданный в качестве параметра. // // Можно заводить любые вспомогаетльные функции, // структуры или даже изменять сигнатуру flatten, // но при этом все примеры вызова из задания должны // компилироваться и работать. template <typename T> void flatten(const Array<T>& array, std::ostream& out); template <typename T> void flatten(const Array< Array<T> > & array, std::ostream& out); template <typename T> void flatten(const Array<T>& array, std::ostream& out) { for (int i = 0; i < array.size(); i++) {

out << array << " "; } } template <typename T> void flatten(const Array< Array<T> > & array, std::ostream& out) { for (int i = 0; i < array.size(); i++) { flatten(array, out); } }

mikemiem
()
Ответ на: комментарий от mikemiem

Прочитал форум на степике, раньше проходило operator delete[](data), но препод сказал, что так не хорошо делать и похоже ввел дополнительный тест, и теперь это не работает.

PS. Я опасаюсь теперь, что кто-то из слушателей прочитает эту ветку не до конца и решит, что «всегда нужно писать operator delete[] вместо delete []», т.к. «иначе это задание не принимается»

Pirr ★★
() автор топика
Последнее исправление: Pirr (всего исправлений: 1)
Ответ на: комментарий от general1
#include <iostream>


// Весь вывод должен осущствляться в поток out,
// переданный в качестве параметра.
//
// Можно заводить любые вспомогаетльные функции,
// структуры или даже изменять сигнатуру flatten,
// но при этом все примеры вызова из задания должны
// компилироваться и работать.
template <typename T>
void flatten(const Array<T>& array, std::ostream& out);
template <typename T>
void flatten(const Array< Array<T> > & array, std::ostream& out);
template <typename T>
void flatten(const Array<T>& array, std::ostream& out)
{
	for (int i = 0; i < array.size(); i++)
	{

		out << array[i] << " ";
	}
}
template <typename T>
void flatten(const Array< Array<T> > & array, std::ostream& out)
{
	for (int i = 0; i < array.size(); i++)
	{
		flatten(array[i], out);
	}
}

.

mikemiem
()
Ответ на: комментарий от mikemiem
struct ICloneable
{
    virtual ICloneable* clone() const = 0;
    virtual ~ICloneable() { }
};

template <typename T>
struct ValueHolder : ICloneable {
    ValueHolder(const T& data): data_(data){}
    T data_;
    ValueHolder * clone() const {
        return new ValueHolder(*this);
    }
};

class Any
{
    ICloneable * ptr;

public:
    Any() : ptr(0) { }
    template <class V>
    Any(const V& v) : ptr(new ValueHolder<V>(v)) { }
    Any(Any const & other) : ptr(other.ptr ? other.ptr->clone() : 0) {}
    Any& operator=(Any const & other)
    {
        delete ptr;
        ptr = 0;
        if (other.ptr)
        {
            ptr = other.ptr->clone();
        }
        return *this;
    }
    template <class A>
    Any& operator=(A const& other)
    {
        delete ptr;
        ptr = 0;
        ptr = new ValueHolder<A>(other);
        return *this;
    }
    ~Any() { delete ptr; }
    template <class T>
    T* cast()
    {
        ValueHolder<T> * vh = dynamic_cast<ValueHolder<T>*>(ptr);
        if (!vh)
            return 0;
        return &(vh->data_);
    }
};
general1
()
Ответ на: комментарий от general1
#include <iostream>


// Весь вывод должен осущствляться в поток out,
// переданный в качестве параметра.
//
// Можно заводить любые вспомогаетльные функции,
// структуры или даже изменять сигнатуру flatten,
// но при этом все примеры вызова из задания должны
// компилироваться и работать.
template <typename T>
void flatten(const Array<T>& array, std::ostream& out);
template <typename T>
void flatten(const Array< Array<T> > & array, std::ostream& out);
template <typename T>
void flatten(const Array<T>& array, std::ostream& out)
{
	for (int i = 0; i < array.size(); i++)
	{

		out << array[i] << " ";
	}
}
template <typename T>
void flatten(const Array< Array<T> > & array, std::ostream& out)
{
	for (int i = 0; i < array.size(); i++)
	{
		flatten(array[i], out);
	}
}[\code]
mikemiem
()
Ответ на: комментарий от general1

#include <cstddef> // size_t

// реализуйте шаблонную функцию array_size, // которая возвращает значение типа size_t.

// put your code here template <class T, size_t N> size_t array_size ( T (&ref)[N] ) { return N; }

general1
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.