I'm writting a small project. I declare a class in the .hpp file and define it in a .cpp file, but when I use it, there is something error about linking.
DSMgr.hpp
#ifndef __DSMGR_HPP__
#define __DSMGR_HPP__
#include "predefine.hpp"
#include <fstream>
#include <string>
class DSMgr{
public:
DSMgr();
int OpenFile(std::string filename); // open the file speciafied by the filename
// and return an error code
int CloseFile(); // close the current file
bFrame ReadPage(const int& page_id); // gain data and return what it reads
int WritePage(const int& page_id, bFrame frm); // called when a page is taken out of buf
// return the number of bytes that be written
int Seek(const int& offset, const int& pos); // move the file pointer to the particular position
fstream& GetFile(); // get the currfile
void IncNumPages(); // increment the numPages
int GetNumPages() const; // return the numPages
void SetUse(const int& index, const int& use_bit); // maintain a global char array which keeps track of
// the use_bits of pages
int GetUse(const int& index) const; // return the use_bit of the particular page
private:
//FILE* currFile;
fstream currFile;
int numPages;
array<int, MAXPAGES> pages;
};
#endif
DSMgr.cpp
#include "../inc/dsmgr.hpp"
inline DSMgr::DSMgr() : numPages(0){ };
inline int DSMgr::OpenFile(std::string filename){
this->currFile.open(filename, ios::out | ios::in | ios::binary);
if(this->currFile.is_open()){
cout << "success: the file " << filename << " open successfully and reserve in the class DSMgr." << endl;
return 1;
}else{
cout << "error: can't open the file." << filename << endl;
abort();
}
}
inline int DSMgr::CloseFile(){
currFile.close();
if(currFile.is_open()){
cout << "error: can't close the current file." << endl;
abort();
}
return 1;
}
inline bFrame DSMgr::ReadPage(const int& page_id){
int pos = page_id * FRAMESIZE;
currFile.seekg(pos, ios::beg);
bFrame read_data;
currFile.read(read_data.field, FRAMESIZE);
return read_data;
}
inline int DSMgr::WritePage(const int& page_id, bFrame frm){
int pos = page_id * FRAMESIZE;
if(currFile.is_open()){
currFile.seekp(pos, ios::beg);
currFile.write(frm.field, strlen(frm.field));
}else{
cout << "error: the current file is not open, fail to write into." << endl;
abort();
}
}
inline int DSMgr::Seek(const int& offset, const int& pos){
if(this->currFile.is_open()){
this->currFile.seekp(pos offset, ios::beg);
return 1;
}else{
cout << "error: the current file is not open so that can not seek file pointer." << endl;
abort();
}
}
#include <thread>
#include <chrono>
// for sleep_for()
inline fstream& DSMgr::GetFile(){
if(this->currFile.is_open()){
return this->currFile;
}else{
cout << "warnning: the current file is not open which may influence getting file." << endl;
std::this_thread::sleep_for(chrono::duration<int>(2));
}
}
inline void DSMgr::IncNumPages(){
this->numPages;
}
inline int DSMgr::GetNumPages() const{
return this->numPages;
}
inline void DSMgr::SetUse(const int& index, const int& use_bit){
// assume that the id of pages mounts from zero
// convert use_bit into char
int use_bit_char = use_bit 48;
use_bits[index] = char(use_bit_char);
}
inline int DSMgr::GetUse(const int& index) const{
int use_bit = int(use_bits[index]) - 48;
return use_bit;
}
predefine.hpp
#ifndef __PREDEFINE_HPP__
#define __PREDEFINE_HPP__
#include <array>
#include <iostream>
using namespace std;
// a block called page in physical memory and frame in buffer.
#define MAXPAGES 50000
#define FRAMESIZE 4096
struct bFrame
{
char field[FRAMESIZE];
};
#define DEFBUFSIZE 1024
extern array<bFrame*, DEFBUFSIZE> buf; // the buf consists of an array of frame
// Buffer Control Blocks
struct BCB{
BCB();
int page_id;
int frame_id;
int latch;
int count;
int dirty;
BCB* next;
};
// the arrays below are defined in the class BMgr
// extern array<int, DEFBUFSIZE> hTable; // frame_id -> page_id
// extern array<BCB, DEFBUFSIZE> hTable_b; // page_id -> BCB
inline const int HashCov(const int& id){ // compute hash value
return (id % DEFBUFSIZE);
}
// double-linked list to manage least recently use list
// assign the head of the list to 'MRU' interface,
// while the tail is 'LRU' interface that should be chosen to replace
#include <list>
static list<int> LM;
// a string that keeps use_bits of pages
static char use_bits[MAXPAGES];
extern int ext;
#endif
testt.cpp
#include "../inc/dsmgr.hpp"
int main(){
DSMgr _dd = DSMgr();
return 0;
}
And the following is error information.
/usr/bin/clang -std=c 14 -fcolor-diagnostics -fansi-escape-codes -g /Users/luzijian/Documents/Document/Ustc/FirstTerm/AdvancedDatabaseSystem/lab/src/*.cpp -o /Users/luzijian/Documents/Document/Ustc/FirstTerm/AdvancedDatabaseSystem/lab/src/../bin/testt
/Users/luzijian/Documents/Document/Ustc/FirstTerm/AdvancedDatabaseSystem/lab/src/dsmgr.cpp:42:1: warning: non-void function does not return a value in all control paths [-Wreturn-type]
}
/Users/luzijian/Documents/Document/Ustc/FirstTerm/AdvancedDatabaseSystem/lab/src/dsmgr.cpp:64:1: warning: non-void function does not return a value in all control paths [-Wreturn-type]
}
2 warnings generated.
Undefined symbols for architecture arm64:
"DSMgr::DSMgr()", referenced from:
_main in testt-a26be3.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
However, when I try to define another class in a test file, it runs successfully.
lru.hpp
#ifndef __LRU_HPP__
#define __LRU_HPP__
class LRU{
public:
int replace(const int& frame_id); // move a frame to the first place if it is not
int add(const int& frame_id); // add a new frame into the list
int select(const int& pos); // select a victim frame and remove it
// the second parameter is to control which frame to return
};
#endif
lru.cpp
#include "../inc/lru.hpp"
#include "../inc/predefine.hpp"
inline int LRU::replace(const int& frame_id){
if(frame_id != LM.front()){
auto pos = find(LM.begin(), LM.end(), frame_id);
int item = *pos;
LM.erase(pos);
LM.push_front(item);
}
return 1;
}
inline int LRU::add(const int& frame_id){
// compare the size of LM list with DEFBUFSIZE
if(DEFBUFSIZE <= LM.size()){
cout << "error: the capacity of LM list is full, can not add a new frame." << endl;
return 0;
}else{
LM.push_front(frame_id);
}
return 1;
}
inline int LRU::select(const int& offset){
auto pos = LM.end();
advance(pos, -offset-1);
return *pos;
}
testt.cpp
#include "../inc/lru.hpp"
int main(){
LRU _ll = LRU();
return 0;
}
When I define the LRU
class in the testt.cpp
file and compile it, there is no error.
Is there anyone can help me solve this problem.
CodePudding user response:
For some reason you have declared everything as inline
. If you want inline
methods then you should move the definitions to the header files.
But if I were you I would just remove inline
from each of your methods.
CodePudding user response:
inline
indicates to the compiler to not export a symbol from a translation unit.
This is useful when defining functions and methods in header files as it avoids multiple symbol definitions when multiple translation units use a header. Each translation unit essentially gets its own copy of the function and there's no conflict (as long as the inline
definitions are included in every translation unit that needs them)
Marking methods inline
in a cpp file however means that your cpp file isn't exporting the symbols for other cpp files to use, this leads to undefined references.