如何在不更改给定代码的情况下将自定义向量<typename> 转换为STL 向量<long> 或从STL 向量<long> 转换?
How to convert a custom vector<typename> to & from an STL vector<long> without changing given code?
我有这个家庭作业问题,我必须为一种名为 GritVM.I 的编造编程语言实现解释器已经构建了程序,并且它按照第一个问题的要求使用 STL List 和 Vector 工作,但在第 2 部分,一个可选问题要求我实现自己的矢量模板 class 并在此 GritVM.hpp & GritVM.cpp 之上实现它(基于原始 STL 的实现)而不更改函数参数或我开始使用的数据成员。
到目前为止,我已经制作了一个名为 ArrayVector 的自定义向量 class。并使用数组数据结构制作了所有基本的ADT向量。我被困在两个地方。我与 STL 之间的转换不起作用。我想知道是否有人可以帮助我。如果您需要更多信息,我可以提供更多代码。提前致谢。
我遇到的错误是:
GritVM.cpp: In member function 'virtual STATUS GritVM::load(std::__cxx11::string, const std::vector<long int>&)':
GritVM.cpp:56:14: error: binding 'const std::vector<long int>' to reference of type 'std::vector<long int>&' discards qualifiers
myDataMem = initialMemory;
^~~~~~~~~~~~~
In file included from GritVM.hpp:7:0:
ArrayVector.hpp:47:18: note: initializing argument 1 of 'ArrayVector<Object>& ArrayVector<Object>::operator=(std::vector<Object>&) [with Object = long int]'
ArrayVector& operator= (std::vector<Object>& stlv){
^~~~~~~~
ArrayVector.hpp: In instantiation of 'std::vector<Object>& ArrayVector<Object>::tempVec_to_stlVec() [with Object = long int]':
GritVM.cpp:17:37: required from here
ArrayVector.hpp:53:41: error: conversion from 'long int*' to non-scalar type 'std::vector<long int>' requested
std::vector<Object> to_stdVec = Arr;
^~~
ArrayVector.hpp:53:29: warning: reference to local variable 'to_stdVec' returned [-Wreturn-local-addr]
std::vector<Object> to_stdVec = Arr;
ArrayVector.hpp
/********ArrayVector.hpp template class************/
/*Base is given by the book author, it includes enum data
for instructions and machine code. I can give you the code for the base file too*/
#include "GritVMBase.hpp"
template<typename Object>
class ArrayVector{
private:
int capacity;
auto num_longElem;
Object* Arr;
protected:
public:
friend class GritVM;
ArrayVector() : capacity(0), num_longElem(0), Arr(nullptr) { }
ArrayVector(std::vector<Object>& stl_vector_para){
Arr = stl_vector_para;
capacity = stl_vector_para.capacity();
num_longElem = stl_vector_para.size();
};
~ArrayVector(){
delete [] Arr;
}
ArrayVector(const ArrayVector& av){
capacity = av.capacity;
num_longElem = av.num_longElem;
Arr = new Object [capacity];
for(auto x = 0; x < num_longElem; ++x){
Arr[x] = av.Arr[x];
}
}
ArrayVector& operator= (ArrayVector& av){
ArrayVector copy = av;
std::swap(*this, copy);
return *this;
}
/***********NOT SURE ABOUT THESE TWO!!!*************/
ArrayVector& operator= (std::vector<Object>& stlv){
ArrayVector copy = stlv;
std::swap(*this, copy);
return *this;
}
std::vector<Object>& tempVec_to_stlVec(ArrayVector& av){
std::vector<Object> to_stdVec = av;
return to_stdVec;
}
/***************************************************/
Object& at(auto index){
if(index < 0 || index > num_longElem){
throw ("Out of bound access.\n");
}
return Arr[index];
}
void erase(auto index){
if(index < 0 || index > num_longElem){
throw ("erase() failed.\n");
}
for(auto x = index + 1; x < num_longElem; ++x){
Arr[x-1] = Arr[x];
}
--num_longElem;
}
void insert(auto index, const Object& le){
if(num_longElem >= capacity){
reserve(std::max(1 , 2*capacity));
}
for(auto x = num_longElem-1; x >= index; --x){
Arr[x+1] = Arr[x];
}
Arr[index] = le;
++num_longElem;
}
/*...then some more basic ADT like size(), empty(), reserve(), empty() etc...*/
};
GritVM.hpp
#include "ArrayVector.hpp"
#include "GritVMBase.hpp"
class GritVM : public GritVMInterface {
private:
long accumulator; /*Stores the result*/
STATUS machineStatus; /*Gets the enum data from Machine Status*/
std::list<Instruction>::iterator currentInstruct; /*Iterator that runs on enum data*/
std::list<Instruction> instructMem;/*Adds the instruction*/
std::vector<long> dataMem; /*Data memory, can't be erased or changed*/
ArrayVector<long> myDataMem; /*TRYING TO GET THIS IMPLEMENTED ALONG SIDE STL VECTOR dataMem*/
long evaluate(Instruction current_instruction); /*Does arithmatic based on instruction*/
void advance(long move_instruction_amount); /*Advances the machine instruction*/
protected:
public:
GritVM(); /*Default constructor*/
~GritVM() { } /* Default destructor*/
/*Assignment realated overridden functions, were pure virtial functions, the parameters can't be changed*/
STATUS load(const std::string filename, const std::vector<long>& initialMemory);
STATUS run();
std::vector<long> getDataMem();
STATUS reset();
};
GritVM.cpp
#include "GritVM.hpp"
GritVM::GritVM() : accumulator(0), machineStatus(WAITING) { }/*Default constructor*/
/*Resets the machine state to default*/
STATUS GritVM::reset() {
accumulator = 0;
machineStatus = WAITING;
//dataMem.clear();
myDataMem.clear(); /**>>>>>HERE<<<<<**/
instructMem.clear();
return machineStatus;
}
/*Returns the current data in the Data Memory*/ /**>>>>>HERE<<<<<**/
std::vector<long> GritVM::getDataMem() {
//return dataMem;
return myDataMem.tempVec_to_stlVec(myDataMem);
}
STATUS GritVM::load(const std::string filename, const std::vector<long>& initialMemory) {
/**Taken away some reading from gvm file to save room***/
/*Copy the memory to data vector*/
//dataMem = initialMemory;
myDataMem= initialMemory; /**>>>>>HERE<<<<<**/
return machineStatus;
}
/*Run instruction for the Grit machine*/
STATUS GritVM::run() {
/***Taken away to save room, is not related to dataMem vector***/
return machineStatus;
}
/*All these evaluate came from the table in the book */
long GritVM::evaluate(Instruction current_instruction) {
long move_instruction_amount = 0; /*Instruction move counter*/
/*******SOME OF THE dataMem are here*******/
switch (current_instruction.operation) {
case AT:
machineStatus = RUNNING;
move_instruction_amount = 1;
//accumulator = dataMem.at(current_instruction.argument);
accumulator = myDataMem.at(current_instruction.argument);
break; /**>>>>>HERE<<<<<**/
case SET:
machineStatus = RUNNING;
move_instruction_amount = 1;
//dataMem.at(current_instruction.argument) = accumulator;
myDataMem.at(current_instruction.argument) = accumulator;
break; /**>>>>>HERE<<<<<**/
case INSERT:
machineStatus = RUNNING;
move_instruction_amount = 1;
//dataMem.insert(current_instruction.argument, accumulator);
myDataMem.insert(current_instruction.argument, accumulator);
break; /**>>>>>HERE<<<<<**/
/***a lot of cases are taken out***/
default:
machineStatus = ERRORED;
break;
}
return move_instruction_amount;
}
/*Takes the instruction, and advancces its amount, given from the pdf file*/
void GritVM::advance(long move_instruction_amount) {
/***taken away to save room, doesn't use dataMem vector****/
}
首先,我建议不要实施您自己的向量。陷阱很多,做对也很复杂。
有很多问题阻碍了转换的发生。
首先,您的 operator=
获取一个向量的可变引用:
// not const -------v
ArrayVector& operator= (std::vector<Object>& stlv){
ArrayVector copy = stlv;
std::swap(*this, copy);
return *this;
}
// v------- not const either
ArrayVector(std::vector<Object>& stl_vector_para){
Arr = stl_vector_para;
capacity = stl_vector_para.capacity();
num_longElem = stl_vector_para.size();
}
采用了可变引用,但您不需要实际改变向量。使它们成为 const 将解决第一个问题,因为您正试图将 const 向量传递给它:
// a reference to a const vector ---v
STATUS load(const std::string filename, const std::vector<long>& initialMemory) {
myDataMem = initialMemory;
// ^----- cannot pass a const vector to a
// function that takes a mutable one
return machineStatus;
}
那么,你有一个终身大事:
// returns by reference
std::vector<Object>& tempVec_to_stlVec(ArrayVector& av) {
// to_stdVec lives until the end of the function
std::vector<Object> to_stdVec = av;
return to_stdVec; // return a reference to an object that will die
}
局部变量不会超出它们的作用域。您正在 return 引用死向量。只需按值 return 代替:
// by value
std::vector<Object> tempVec_to_stlVec(ArrayVector& av) {
// to_stdVec lives until the end of the function
std::vector<Object> to_stdVec = av;
return to_stdVec; // return the object by value
}
Return 值优化将负责使 return 按值高效化。如果无法完成该优化,移动构造函数将处理它。
然后我看到了发布的错误中没有的错误。
向量不能转换成指针:
Arr = stl_vector_para;
这样不行。如果你真的想制作自己的向量class,你必须手动进行动态分配和复制数据。
C++ 提供这些数据结构是有原因的:让我们的生活更轻松,让 C++ 变得有趣。除非您知道自己在做什么,否则实现自己的向量通常很痛苦。
我有这个家庭作业问题,我必须为一种名为 GritVM.I 的编造编程语言实现解释器已经构建了程序,并且它按照第一个问题的要求使用 STL List 和 Vector 工作,但在第 2 部分,一个可选问题要求我实现自己的矢量模板 class 并在此 GritVM.hpp & GritVM.cpp 之上实现它(基于原始 STL 的实现)而不更改函数参数或我开始使用的数据成员。
到目前为止,我已经制作了一个名为 ArrayVector 的自定义向量 class。并使用数组数据结构制作了所有基本的ADT向量。我被困在两个地方。我与 STL 之间的转换不起作用。我想知道是否有人可以帮助我。如果您需要更多信息,我可以提供更多代码。提前致谢。
我遇到的错误是:
GritVM.cpp: In member function 'virtual STATUS GritVM::load(std::__cxx11::string, const std::vector<long int>&)':
GritVM.cpp:56:14: error: binding 'const std::vector<long int>' to reference of type 'std::vector<long int>&' discards qualifiers
myDataMem = initialMemory;
^~~~~~~~~~~~~
In file included from GritVM.hpp:7:0:
ArrayVector.hpp:47:18: note: initializing argument 1 of 'ArrayVector<Object>& ArrayVector<Object>::operator=(std::vector<Object>&) [with Object = long int]'
ArrayVector& operator= (std::vector<Object>& stlv){
^~~~~~~~
ArrayVector.hpp: In instantiation of 'std::vector<Object>& ArrayVector<Object>::tempVec_to_stlVec() [with Object = long int]':
GritVM.cpp:17:37: required from here
ArrayVector.hpp:53:41: error: conversion from 'long int*' to non-scalar type 'std::vector<long int>' requested
std::vector<Object> to_stdVec = Arr;
^~~
ArrayVector.hpp:53:29: warning: reference to local variable 'to_stdVec' returned [-Wreturn-local-addr]
std::vector<Object> to_stdVec = Arr;
ArrayVector.hpp
/********ArrayVector.hpp template class************/
/*Base is given by the book author, it includes enum data
for instructions and machine code. I can give you the code for the base file too*/
#include "GritVMBase.hpp"
template<typename Object>
class ArrayVector{
private:
int capacity;
auto num_longElem;
Object* Arr;
protected:
public:
friend class GritVM;
ArrayVector() : capacity(0), num_longElem(0), Arr(nullptr) { }
ArrayVector(std::vector<Object>& stl_vector_para){
Arr = stl_vector_para;
capacity = stl_vector_para.capacity();
num_longElem = stl_vector_para.size();
};
~ArrayVector(){
delete [] Arr;
}
ArrayVector(const ArrayVector& av){
capacity = av.capacity;
num_longElem = av.num_longElem;
Arr = new Object [capacity];
for(auto x = 0; x < num_longElem; ++x){
Arr[x] = av.Arr[x];
}
}
ArrayVector& operator= (ArrayVector& av){
ArrayVector copy = av;
std::swap(*this, copy);
return *this;
}
/***********NOT SURE ABOUT THESE TWO!!!*************/
ArrayVector& operator= (std::vector<Object>& stlv){
ArrayVector copy = stlv;
std::swap(*this, copy);
return *this;
}
std::vector<Object>& tempVec_to_stlVec(ArrayVector& av){
std::vector<Object> to_stdVec = av;
return to_stdVec;
}
/***************************************************/
Object& at(auto index){
if(index < 0 || index > num_longElem){
throw ("Out of bound access.\n");
}
return Arr[index];
}
void erase(auto index){
if(index < 0 || index > num_longElem){
throw ("erase() failed.\n");
}
for(auto x = index + 1; x < num_longElem; ++x){
Arr[x-1] = Arr[x];
}
--num_longElem;
}
void insert(auto index, const Object& le){
if(num_longElem >= capacity){
reserve(std::max(1 , 2*capacity));
}
for(auto x = num_longElem-1; x >= index; --x){
Arr[x+1] = Arr[x];
}
Arr[index] = le;
++num_longElem;
}
/*...then some more basic ADT like size(), empty(), reserve(), empty() etc...*/
};
GritVM.hpp
#include "ArrayVector.hpp"
#include "GritVMBase.hpp"
class GritVM : public GritVMInterface {
private:
long accumulator; /*Stores the result*/
STATUS machineStatus; /*Gets the enum data from Machine Status*/
std::list<Instruction>::iterator currentInstruct; /*Iterator that runs on enum data*/
std::list<Instruction> instructMem;/*Adds the instruction*/
std::vector<long> dataMem; /*Data memory, can't be erased or changed*/
ArrayVector<long> myDataMem; /*TRYING TO GET THIS IMPLEMENTED ALONG SIDE STL VECTOR dataMem*/
long evaluate(Instruction current_instruction); /*Does arithmatic based on instruction*/
void advance(long move_instruction_amount); /*Advances the machine instruction*/
protected:
public:
GritVM(); /*Default constructor*/
~GritVM() { } /* Default destructor*/
/*Assignment realated overridden functions, were pure virtial functions, the parameters can't be changed*/
STATUS load(const std::string filename, const std::vector<long>& initialMemory);
STATUS run();
std::vector<long> getDataMem();
STATUS reset();
};
GritVM.cpp
#include "GritVM.hpp"
GritVM::GritVM() : accumulator(0), machineStatus(WAITING) { }/*Default constructor*/
/*Resets the machine state to default*/
STATUS GritVM::reset() {
accumulator = 0;
machineStatus = WAITING;
//dataMem.clear();
myDataMem.clear(); /**>>>>>HERE<<<<<**/
instructMem.clear();
return machineStatus;
}
/*Returns the current data in the Data Memory*/ /**>>>>>HERE<<<<<**/
std::vector<long> GritVM::getDataMem() {
//return dataMem;
return myDataMem.tempVec_to_stlVec(myDataMem);
}
STATUS GritVM::load(const std::string filename, const std::vector<long>& initialMemory) {
/**Taken away some reading from gvm file to save room***/
/*Copy the memory to data vector*/
//dataMem = initialMemory;
myDataMem= initialMemory; /**>>>>>HERE<<<<<**/
return machineStatus;
}
/*Run instruction for the Grit machine*/
STATUS GritVM::run() {
/***Taken away to save room, is not related to dataMem vector***/
return machineStatus;
}
/*All these evaluate came from the table in the book */
long GritVM::evaluate(Instruction current_instruction) {
long move_instruction_amount = 0; /*Instruction move counter*/
/*******SOME OF THE dataMem are here*******/
switch (current_instruction.operation) {
case AT:
machineStatus = RUNNING;
move_instruction_amount = 1;
//accumulator = dataMem.at(current_instruction.argument);
accumulator = myDataMem.at(current_instruction.argument);
break; /**>>>>>HERE<<<<<**/
case SET:
machineStatus = RUNNING;
move_instruction_amount = 1;
//dataMem.at(current_instruction.argument) = accumulator;
myDataMem.at(current_instruction.argument) = accumulator;
break; /**>>>>>HERE<<<<<**/
case INSERT:
machineStatus = RUNNING;
move_instruction_amount = 1;
//dataMem.insert(current_instruction.argument, accumulator);
myDataMem.insert(current_instruction.argument, accumulator);
break; /**>>>>>HERE<<<<<**/
/***a lot of cases are taken out***/
default:
machineStatus = ERRORED;
break;
}
return move_instruction_amount;
}
/*Takes the instruction, and advancces its amount, given from the pdf file*/
void GritVM::advance(long move_instruction_amount) {
/***taken away to save room, doesn't use dataMem vector****/
}
首先,我建议不要实施您自己的向量。陷阱很多,做对也很复杂。
有很多问题阻碍了转换的发生。
首先,您的 operator=
获取一个向量的可变引用:
// not const -------v
ArrayVector& operator= (std::vector<Object>& stlv){
ArrayVector copy = stlv;
std::swap(*this, copy);
return *this;
}
// v------- not const either
ArrayVector(std::vector<Object>& stl_vector_para){
Arr = stl_vector_para;
capacity = stl_vector_para.capacity();
num_longElem = stl_vector_para.size();
}
采用了可变引用,但您不需要实际改变向量。使它们成为 const 将解决第一个问题,因为您正试图将 const 向量传递给它:
// a reference to a const vector ---v
STATUS load(const std::string filename, const std::vector<long>& initialMemory) {
myDataMem = initialMemory;
// ^----- cannot pass a const vector to a
// function that takes a mutable one
return machineStatus;
}
那么,你有一个终身大事:
// returns by reference
std::vector<Object>& tempVec_to_stlVec(ArrayVector& av) {
// to_stdVec lives until the end of the function
std::vector<Object> to_stdVec = av;
return to_stdVec; // return a reference to an object that will die
}
局部变量不会超出它们的作用域。您正在 return 引用死向量。只需按值 return 代替:
// by value
std::vector<Object> tempVec_to_stlVec(ArrayVector& av) {
// to_stdVec lives until the end of the function
std::vector<Object> to_stdVec = av;
return to_stdVec; // return the object by value
}
Return 值优化将负责使 return 按值高效化。如果无法完成该优化,移动构造函数将处理它。
然后我看到了发布的错误中没有的错误。
向量不能转换成指针:
Arr = stl_vector_para;
这样不行。如果你真的想制作自己的向量class,你必须手动进行动态分配和复制数据。
C++ 提供这些数据结构是有原因的:让我们的生活更轻松,让 C++ 变得有趣。除非您知道自己在做什么,否则实现自己的向量通常很痛苦。