(c ++) переопределяющий оператор << печатает неверный объект - PullRequest
0 голосов
/ 09 декабря 2018

Сейчас я делаю переопределение оператора для скаляра и вектора и борюсь с оператором << </p>

Вот мой код сначала

main: (Я не могу изменить основной ... он будетдаются так, и я только код cpVector, cpScalar)

#include <iostream>
#include "cpScalar.hpp"
#include "cpVector.hpp"
#include <iostream>
#include <string>

using namespace std;

int main(){

cpScalar arr[4];
for(int i = 0; i < 4; i++){
    arr[i] = cpScalar(i+1);
}
cpVector v1(arr, 4);          // {1, 2, 3, 4}
cpScalar arr2[4];
for(int i = 0; i < 4; i++){
    arr2[i] = cpScalar(i+3);
}
cpVector v2(arr2, 4);         // {3, 4, 5, 6}

cpVector result4 = v2 / v1;   //  {0.3, 0.4, 0.5, 0.6}

cout << result4.getVal(0) << " " ... " "  << result4.getVal(3) << endl;
cout << result4 << endl;
// prints   0.3, 0.4, 0.5, 0.6   and     [, , , ]
}

Когда я проверяю каждое значение результата 4, я могу найти оператор / работало.Однако, когда я пытаюсь напечатать весь вектор, он печатает пустое значение.Вот класс cpVector.

cpVector:

#ifndef CPVECTOR_H
#define CPVECTOR_H
#include "cpScalar.hpp"
#include <iostream>
#include <string>
#include <cassert>

using namespace std;
class cpVector
{
    private:
        cpScalar *data;
        unsigned int size;

    public:
        cpVector() {
            cpScalar s[0];
            data = s;
            size = 0;
        }

        cpVector(cpScalar sarr[], unsigned int s){
            this->size = s;
            data = sarr;
        }

        cpVector operator/(cpVector s){
            assert(size == s.getSize());

            unsigned int x = s.getSize();
            cpScalar denom = s.getAbs();
            cpScalar ans[x];
            for (int i=0; i < x;i++){
                ans[i] = data[i] / denom;
                std::cout << i << "th element: " << ans[i] << std::endl;
            }
            return cpVector(ans, x);
        }

        friend std::ostream& operator<<(std::ostream& s, const cpVector &r);

        cpScalar getVal(int i)const{return data[i];}

        int getSize() const{return size;}

        cpScalar getAbs() const{
            cpScalar sum(0);
            for(int i = 0; i < size; i++){
                cpScalar x = data[i];
                if(x.getDouble() < 0 && x.getInt() < 0){
                    x = x * cpScalar(-1);
                }
                sum = sum + x;
            }
            return sum;
        }
};

std::ostream& operator<<(std::ostream& s, const cpVector &r) {
            s.put('[');
            if(r.getSize() > 0){
                s << r.getVal(0);
                for (int i = 1; i < r.getSize(); i++) {
                    s << ", " << r.getVal(i);
                }
            }
            return s << ']';
        };

#endif // CPVECTOR_H

cpScalar:

#ifndef CPSCALAR_H
#define CPSCALAR_H
#include <iostream>
#include <string>
#include <cassert>

const int invalid = 99999999;

class cpScalar
{
     private:
        int intData;
        double doubData;
        char dType;

    public:
        cpScalar() {
            intData = invalid;
            doubData = invalid;
            dType = ' ';
        }
        cpScalar(int d) {
            intData = d;
            doubData = invalid;
            dType = 'i';
        }
        cpScalar(double d) {
            intData = invalid;
            doubData = d;
            dType = 'd';
        }

        cpScalar operator+ (cpScalar &s){
            if (getType() == 'i' && s.getType() == 'i'){
                return cpScalar(getInt() + s.getInt());
            }else if (getType() == 'd' && s.getType() == 'i'){
                return cpScalar(getDouble() + s.getInt());
            }else if (getType() == 'i' && s.getType() == 'd'){
                return cpScalar(getInt() + s.getDouble());
            } else if (getType() == 'd' && s.getType() == 'd'){
                return cpScalar(getDouble() + s.getDouble());
            }
            return cpScalar(invalid);
        }

        cpScalar operator/ (cpScalar s){
            assert(s.getDouble() != 0 && s.getInt() != 0);

            if (getType() == 'i' && s.getType() == 'i'){
                if(getInt() % s.getInt() == 0) return cpScalar(getInt() / s.getInt());
                else return cpScalar(1.0 * getInt() / s.getInt());
            }else if (getType() == 'd' && s.getType() == 'i'){
                return cpScalar(getDouble() / s.getInt());
            }else if (getType() == 'i' && s.getType() == 'd'){
                return cpScalar(getInt() / s.getDouble());
            } else if (getType() == 'd' && s.getType() == 'd'){
                return cpScalar(getDouble() / s.getDouble());
            }
            return cpScalar(invalid);
        }

        cpScalar operator* (cpScalar s){
            if (getType() == 'i' && s.getType() == 'i'){
                return cpScalar(getInt() * s.getInt());
            }else if (getType() == 'd' && s.getType() == 'i'){
                return cpScalar(getDouble() * s.getInt());
            }else if (getType() == 'i' && s.getType() == 'd'){
                return cpScalar(getInt() * s.getDouble());
            } else if (getType() == 'd' && s.getType() == 'd'){
                return cpScalar(getDouble() * s.getDouble());
            }
            return cpScalar(invalid);
        }

        friend std::ostream& operator<< (std::ostream &sout, const cpScalar &d);

        int getInt() const{return intData;}

        double getDouble() const{return doubData;}

        char getType() const{return dType;}

};
        std::ostream& operator<<(std::ostream &sout, const cpScalar &d) {
            if(d.getType() == 'i') sout << d.getInt();
            else if (d.getType() == 'd') sout << d.getDouble();
            return sout;
        };
#endif // CPSCALAR_H

Спасибо за чтение

1 Ответ

0 голосов
/ 10 декабря 2018

Нельзя хранить указатель на временную переменную, размещенную в стеке.Когда временный элемент перестает существовать в конце своей области видимости, указатель больше не действителен.

Например, со следующим кодом (обратите внимание, для краткости я пропустил инициализацию значений массива в этих примерах):

struct Foo
{
  int* data;
  Foo( int* d )
  : data( d )
  {
  }
};

Foo makeFoo( size_t size )
{
  int bar[ size ]; // note this in invalid c++, only allowed by a gcc extension
  return Foo( bar );
}

int main()
{
  Foo f = makeFoo( 4 );
  std::cout << f.data[ 0 ]; // undefined behaviour, f.data points to and array that no longer exists
}

Массив bar не существует после окончания makeFoo, а возвращенный указатель Foo data указывает на память, которая была освобождена.Обратите внимание, что если вы запустите приведенный выше код, он, скорее всего, выведет правильный вывод, так как хотя массив больше не существует, его значения не будут перезаписаны, так как никакая другая функция не будет использовать стек до того, как мы распечатаем вывод.

Наиболее C ++ решение этой проблемы - использовать std::vector:

struct Foo
{
  std::vector< int > data;
  Foo( const std::vector< int >& data )
  : data( d ) // make a copy of the temporary vector, no more undefined behaviour
  {
  }
};

Foo makeFoo( size_t size )
{
  std::vector< int > bar( size );
  return Foo( bar );
}

Если ваше задание не позволяет вам использовать std::vector (я ненавижу задания, которые пытаются научить вас C ++, не позволяя вамчтобы использовать ключевые функции языка и стандартной библиотеки), вам нужно будет использовать указатели:

struct Foo
{
  int* data;
  Foo( int* d )
  : data( d )
  {
  }
};

Foo makeFoo( size_t size )
{
  int* bar = new int[ size ];
  return Foo( bar );
}

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

Чтобы избежать этой проблемы, мы должны использовать std::unique_ptr, который удаляет массивдля нас и избегает правила 3/5 выпуска:

struct Foo
{
    std::unique_ptr< int[] > data;
    Foo(std::unique_ptr< int[] >&& d)
        : data( std::move( d ) )
    {
    }
};

Foo makeFoo(size_t size)
{
    std::unique_ptr< int[] > bar( new int[ size ] ); 
    return Foo( std::move( bar ) );
}

Обратите внимание, что невозможно скопировать std::unique_ptr, мы должны использовать std::move для перемещения значенийа не копировать их.Вам также потребуется использовать std::move: для перемещения объектов Foo, а не для их копирования.См. https://en.cppreference.com/w/cpp/language/move_constructor для получения информации о том, как движущиеся объекты работают в C ++ (может быть немного продвинутым для новичка, но это ключевая особенность современного C ++).Если вы не можете разобраться с движущимися объектами, вы можете вместо этого использовать std::shared_ptr (просто замените std::unique_ptr на std::shared_ptr в приведенном выше примере и удалите std::move s), который можно копировать, но учтите, что если вы копируетеFoo объект, обе копии будут указывать на одинаковые данные.

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