-1

I declared a member function called push_back in the .h file and write it in .cpp file. However, when I tried to called it, it says undefined reference I am sorry, I am still new to C++. Thank you very much!

The compiler gives me the following error:

undefined reference to `StrVec::push_back(std::__cxx11::basic_string<char, std::char_traits, std::allocator > const&)'
collect2.exe: error: ld returned 1 exit status

// StrVec.h 
#ifndef STRVEC_H
#define STRVEC_H //change name depend on file

#include <string>
#include <memory>
#include <utility>
class StrVec
{
public:
  StrVec() : // the allocator member is default initialized
             elements(nullptr), first_free(nullptr), cap(nullptr)
  {
  }
  StrVec(const StrVec &);              // copy constructor
  StrVec &operator=(const StrVec &);   // copy assignment
  ~StrVec(){}                           // destructor
  void push_back(const std::string &); // copy the element
  size_t size() const { return first_free - elements; }
  size_t capacity() const { return cap - elements; }
  std::string *begin() const { return elements; }
  std::string *end() const { return first_free; }

  // define move constructor
  Strvec(StrVec &&);

  // define move operator
  StrVec &operator=(StrVec&&);
  // ...
private:
  std::allocator<std::string> alloc; // allocates the elements
  // used by the functions that add elements to the StrVec

  void chk_n_alloc()
  {
    if (size() == capacity())
      reallocate();
  }
  // utilities used by the copy constructor, assignment operator, and destructor

  std::pair<std::string *, std::string *> alloc_n_copy(const std::string *, const std::string *);
  void free();             // destroy the elements and free the space
  void reallocate();       // get more space and copy the existing elements
  std::string *elements;   // pointer to the first element in the array
  std::string *first_free; // pointer to the first free element in the array
  std::string *cap;        // pointer to one past the end of the array
};

#endif

// StrVec.cpp
#include "Strvec.h"

StrVec::push_back(const std::string &mes)
{
  
  chk_n_alloc(); // ensure that there is room for another element
  // construct a copy of s in the element to which first_free points
  alloc.construct(first_free++, mes);
}

std::pair<std::string *, std::String *> StrVec::alloc_n_copy(const string *beg, const string *end)
{
  auto data = alloc.allocate(end - beg); // allow enought memory, use during copy operator

  // return two string pointer, represent the begin and end of alloc
  return {data, std::uninitialized_copy(beg, end, data)};
}

void Strvec::free()
{
  // free memory
  // used in destructor
  for (auto p = first_free, p != elements;)
  {
    alloc.destroy(--p); //uninitalize this memory
  }
  alloc.f = deallocate(elements, cap - elements); // finally free out thos memory from allocator
}

StrVec::Strvec(const Strvec &s)
{
  // copy constructor
  auto returnedPairs = alloc_n_copy(s.begin(), s.end());
  elements = returnedPairs.first;
  first_free = cap = returnedPairs.second; //since
}
Strvec::~Strvec()
{
  free();
}

Strvec &Strvec::operator=(const Strvec &data)
{
  //1. save data
  auto datas = alloc_n_copy(data.begin(), data.end());
  //2. free memory
  free();
  // 3. reassign
  elements = datas.first;
  first_free = cap = datas.second;
  return *this;
}

//allocator function
// since we are going to copy old value from old allocator to this new allocator we building

// however, we are using the moving function by calling std::move, to avoid the need of copy
//calling std::move() signals that it use move constructor, not a copy constructor
    // move constructor is like passing the pointer/unique_ptr of that object to another, do not take upe extra memory!
StrVec::reallocate()
{
  auto newcapacity = size() ? 2 * size() : 1; // a container twice the size as before

  auto newdata = alloc.allocate(newcapacity);

  // move the data from the old memory to the new
  auto dest = newdata;        // points to the next free position in the new
  array auto elem = elements; // points to the next element in the old array

  for (size_t i = 0; i != size(); ++i)
    alloc.construct(dest++, std::move(*elem++));
  free(); // free the old space once we've moved the elements
  // update our data structure to point to the new elements
  elements = newdata;
  first_free = dest;
  cap = elements + newcapacity;
}


// note: both move does nothing to this->alloc
      // because the program is trying to avoid making copy of that objects
// note: need to use noexcept to skip checking in compiler and etc, see page 665
StrVec::Strvec(StrVec &&s) noexcept : elements(s.elements), first_free(s.first_free), cap(s.cap){  // move won't throw any eceptions
  // leave s in a state which it is safe to run the destructor

  // remember, calling move meaning we plan to delete that object
  // alloc can get by std::move(alloc)
  s.first_free= s.elements = s.cap = nullptr;
}

// define move operator
StrVec & StrVec::operator=(StrVec&& rhs) noexcept{
  // check for self-assignation, because it is no need in this point
  if(this != &rhs){
    free(); // free exist elements in this class
    elements = rhs.elements;
    cap = rhs.cap;
    first_free = rhs.first_free;


    // leave rhs in a destructiable state
    rhs.cap = rhs.elements = rhs.first_free = nullptr;
  }

  return *this;
}

// main function
int main(){

  StrVec h;
  string s="21";
  h.push_back(s);
return 0;
}
shouyu du
  • 3
  • 2
  • 1
    First, you should fix compile errors. `StrVec::push_back`, `Strvec(StrVec &&)`, `StrVec::Strvec`, `Strvec::~Strvec()` and many other are not valid. – 273K Jul 28 '21 at 04:09
  • I was able to fix the compile error for StrVec::push_back. However, the compiler still give me undefined reference to Strvec(StrVec &&), StrVec::Strvec, Strvec::~Strvec(). I have not idea where did I wrote wrong? Can you give me insight or direction on how should I correct it? Thanks! – shouyu du Jul 29 '21 at 03:18

1 Answers1

0

If you are separating declaration and defination in .h and .cpp correspondingly there are couple of rules which needs to be taken care of .

header Rules

Enter return type like this

void StrVec::push_back(const std::string &mes)
{
  
  chk_n_alloc(); // ensure that there is room for another element
  // construct a copy of s in the element to which first_free points
  alloc.construct(first_free++, mes);
}
User
  • 572
  • 2
  • 10