在复制构造函数中用垃圾值初始化的变量

Variable initialized with garbage value in copy constructor

在我的 comp sci class 中,我们正在制作矢量 class。我被卡住了,因为我的复制构造函数正在用垃圾值初始化我的 'limit' 变量,我不明白为什么。

这是我的主要内容:

myStringVector v1 {"a", "b", "c"};
std::cout << "make it here?" << std::endl;
myStringVector v2 = v1;
std::cout << v1[0] << v1[1] << v1[2] << std::endl;
std::cout << v2[0] << v2[1] << v2[2] << std::endl;
assert(v1 == v2);
std::cout << "Passed copy ctor" << std::endl;

这是一个构造函数,它接受一个 initializer_list

myStringVector::myStringVector(std::initializer_list<myString> list){
   this->reserve(list.size());
   for(int i = 0; i < limit-1; i++){
     construct(first+i, list.begin()[i]);
   }
}

这里是拷贝构造函数

myStringVector::myStringVector(const myStringVector& data){
  reserve((data.limit)-1);
  for(int i = 0; i < data.limit-1; i++){
    construct(&first+i, data.first+i);
  }
}

这是储备的样子

void myStringVector::reserve(int n){
  this->first = allocate<myString>(n);
  this->last = first+n;
  this->limit = n+1;
}

我在 main 中的断言失败了,因为我重载了 == 运算符以首先检查限制是否相等。如果不是,则函数 return 为假。该函数在那之后继续,但断言失败,因为我将我的 v1 设置为 4,这是正确的,然后我的 v2 是一些没有意义的大数字。

我已经尝试重写我的复制构造函数以直接初始化 class 的成员而不使用保留,但它仍然不起作用。它仍然在为 limit 分配垃圾值。其余部分工作正常。

这是 main 输出的内容...

能到这里吗?

abc

abc

4 7500072

断言失败:v1 == v2,文件 myCodeTres.cpp,第 58 行

我觉得我已经尝试了所有我能想到的方法来尝试解决这个问题,但没有任何效果。对我有什么建议吗?

谢谢。

更新:这些是我在省略 & 符号时遇到的编译器错误。

在 myCodeTres.cpp 包含的文件中:20: myMemory.hpp:在 'T* construct(T*, Args&& ...) [with T = myString; Args = {myString*}]' 的实例化中: myStringVector.cpp:25:36: 从这里需要 myMemory.hpp:61:10: 错误:没有匹配函数来调用 'myString::myString(myString*)' 61 | return new (p) T(std::forward(args)...); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

**然后在编译器屏幕上出现一些蓝色的奇怪错误**

在 myCodeTres.cpp 包含的文件中:23: myString.cpp:42:1: 注:候选人:'myString::myString(myString&&)' 42 | myString::myString(myString&& move) : strLength(strlen(move.stringVar)) //移动构造函数以从中移动内容 | ^~~~~~~~ myString.cpp:42:31:注意:参数 1 没有从 'myString*' 到 'myString&&' 的已知转换 42 | myString::myString(myString&& move) : strLength(strlen(move.stringVar)) //移动构造函数以从中移动内容 | ~~~~~~~~~~~^~~~ myString.cpp:32:1: 注:候选人:'myString::myString(const myString&)' 32 | myString::myString(const myString& strToCpy) : strLength(strlen(strToCpy.stringVar)) //删除旧元素的复制构造函数 | ^~~~~~~~ myString.cpp:32:36:注意:参数 1 没有从 'myString*' 到 'const myString&' 的已知转换 32 | myString::myString(const myString& strToCpy) : strLength(strlen(strToCpy.stringVar)) //删除旧元素的复制构造函数 | ~~~~~~~~~~~~~~~~^~~~~~~~ 在 myCodeTres.cpp:23 包含的文件中: myString.cpp:23:1: 注:候选人:'myString::myString(const char*, std::size_t)' 23 | myString::myString(const char* cPnt, std::size_t size) : strLength(size) // 获取大小和 const ptr 到 char 的构造函数 | ^~~~~~~~ myString.cpp:23:1: 注意:候选人需要 2 个参数,提供 1 个 myString.cpp:14:1: 注:候选人:'myString::myString(const char*)' 14 | myString::myString(const char* cPnt) : strLength(strlen(cPnt)) //构造函数以将给定的 const ptr 初始化为 char。 | ^~~~~~~~ myString.cpp:14:32:注意:参数 1 没有从 'myString*' 到 'const char*' 的已知转换 14 | myString::myString(const char* cPnt) : strLength(strlen(cPnt)) //构造函数以将给定的 const ptr 初始化为 char。 | ~~~~~~~~~~~~^~~~ myString.cpp:8:1: 注:候选人:'myString::myString()' 8 | myString::myString() //默认构造函数:初始化空字符串。 | ^~~~~~~~ myString.cpp:8:1: 注意:候选人需要 0 个参数,提供 1 个

更新:整个class定义

 #ifndef MYSTRINGVECTOR_HPP
 #define MYSTRINGVECTOR_HPP

  #include "myString.hpp"
  #include <initializer_list>

  class myStringVector{
  private:
  myString *first, *last;
  int limit = 0;
  public:
  void reserve(int); //allocate memory at 'first' for n myString's
  myStringVector(); //call to reserve(0)
  myStringVector(std::initializer_list<myString>);
  myStringVector(const myStringVector&);
  bool empty();
  bool operator==(const myStringVector&);
  myString operator[](int);
  int getSize() const;
};

#endif //MYSTRINGVECTOR_HPP_INCLUDED

.cpp 文件

#include "myStringVector.hpp"
#include "myMemory.hpp"
#include <initializer_list>

void myStringVector::reserve(int n){
  this->first = allocate<myString>(n);
  this->last = first+n;
  this->limit = n+1;
}

myStringVector::myStringVector(){
 this->reserve(0);
 } 

 myStringVector::myStringVector(std::initializer_list<myString> list){
 this->reserve(list.size());
 for(int i = 0; i < limit-1; i++){
  construct(first+i, list.begin()[i]);
 }
 }

myStringVector::myStringVector(const myStringVector& data){
 reserve((data.limit)-1);
  for(int i = 0; i < data.limit-1; i++){
    construct(first+i, data.first+i);
 }
}

bool myStringVector::empty(){
  return (limit-1 == 0);
}

 bool myStringVector::operator==(const myStringVector& data){
 std::cout << limit << " " << data.limit << std::endl;
  if(this->limit != data.limit)
   return 0;
  for(int i = 0; i < limit; i++){
    if(*(first+i) != *(data.first+i))
      return 0;
  }
 return 1;
}

myString myStringVector::operator[](int index){
  return *(first+index);
}

int myStringVector::getSize() const{
  return limit-1;
}

格式化有点不对劲,因为将代码上传到 Whosebug 非常乏味。

复制构造函数中的简单错误

construct(&first+i, data.first+i);

应该是

construct(first+i, data.first+i);

编辑

这来自初始化列表构造函数。

construct(first+i, list.begin()[i]);

现在仔细想想这里的类型。第一个参数很简单,它是指向 myString 的指针,即 myString*。第二个有点复杂,因为您必须理解 std::initializer_list,但如果您按照它进行操作,它就是对 myString 的 const 引用,即 const myString&。现在这很好,因为 construct 是这样定义的

template <class T>
void construct(T* first, const T& second);

即对于某些类型 T 它的第一个参数是指向该类型的指针,第二个参数是对该类型的常量引用。

现在看看第二次使用的类型construct(不编译的那个)

construct(first+i, data.first+i);

第一个参数是myString*,第二个参数是const myString*。两点指点!这就是它不编译的原因!您的解决方案是向第一个参数添加一个额外的指针。

的类型
construct(&first+i, data.first+i);

myString**const myString*。编译是因为你在左边有一个双指针,在右边有一个指针,但这意味着你正在构造指向 myString 而不是 myString 对象的指针,这不是你想要的。

您应该做的是从第二个参数中删除 指针,而不是向第一个参数添加额外的指针。换句话说,正确的代码是这个

construct(first+i, data.first[i]);

现在第一个参数的类型为 myString*,第二个参数的类型为 const myString&。与其他构造函数完全相同。

试试这个改变,让我知道它是怎么回事。