Home > database >  creating a class vector that does not delete it's content
creating a class vector that does not delete it's content

Time:12-22

I am a beginner , so i wanted to ask , can we create a class object vector/array , that does not delete it's content when i close the program like , so like I want a customer record , but whenever if we try to restart the program we need to enter the customer details again and again ... how to prevent that from happening

#include <iostream>
#include <vector>

using namespace std;
class customer{

    public:
    int balance;

    string name;
    int password;
};
int main(){
    vector <customer> cus;
    

    ... 

    if(choice == 1){
        cout << cus[i].balance
    }
    return 0;
}

CodePudding user response:

As a complement to Adam's answer, it is possible to encapsulate the serialization in the container class itself. Here is an simplified example:

The header file defining a persistent_vector class that saves its content to a file:

#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <initializer_list>

namespace {
    // Utility functions able to store one element of a trivially copyable type
    template <class T>
    std::ostream& store1(std::ostream& out, const T& val) {
        out.write(reinterpret_cast<const char*>(&val), sizeof(val));
        return out;
    }

    template <class T>
    std::istream& load1(std::istream& in, T& val) {
        in.read(reinterpret_cast<char*>(&val), sizeof(val));
        return in;
    }

    // Specialization for the std::string type
    template <>
    std::ostream& store1<std::string>(std::ostream& out, const std::string& val) {
        store1<size_t>(out, val.size());
        if (out) out.write(val.data(), val.size());
        return out;
    }

    template <>
    std::istream& load1<std::string>(std::istream& in, std::string& val) {
        size_t len;
        load1<size_t>(in, len);
        if (in) {
            char* data = new char[len];
            in.read(data, len);
            if (in) val.assign(data, len);
            delete[] data;
        }
        return in;
    }
}

template <class T>
class persistent_vector {
    const std::string path;
    std::vector<T> vec;

    // load the vector from a file
    void load() {
        std::ifstream in(path);
        if (in) {
            for (;;) {
                T elt;
                load1(in, elt);
                if (!in) break;
                vec.push_back(elt);
            }
            if (!in.eof()) {
                throw std::istream::failure("Read error");
            }
            in.close();
        }
    }

    // store the vector to a file
    void store() {
        std::ofstream out(path);
        size_t n = 0;
        if (out) {
            for (const T& elt : vec) {
                store1(out, elt);
                if (!out) break;
                  n;
            }
        }
        if (!out) {
            std::cerr << "Write error after " << n << " elements on " << vec.size() << '\n';
        }
    }

public:
    // a bunch of constructors, first ones load data from the file
    persistent_vector(const std::string& path) : path(path) {
        load();
    }
    persistent_vector(const std::string& path, size_t sz) :
        path(path), vec(sz) {
        load();
    };
    // last 2 constructors ignore the file because they do receive data
    persistent_vector(const std::string& path, size_t sz, const T& val) :
        path(path), vec(sz, val) {
    };
    persistent_vector(const std::string& path, std::initializer_list<T> ini) :
        path(path), vec(ini) {
    }

    // destructor strores the data to the file before actually destroying it
    ~persistent_vector() {
        store();
    }

    // direct access to the vector (const and non const versions)
    std::vector<T>& data() {
        return vec;
    }
    const std::vector<T>& data() const {
        return vec;
    }
};

It can, out of the box, handle any trivially copyable type and std::string. User has to provide specializations of store1 and load1 for custom types.

Here is a trivial program using it:

#include <iostream>
#include <string>

#include "persistent_vector.h"

int main() {
    std::cout << "Create new vector (0) or read an existing one (1): ";
    int cr;
    std::cin >> cr;
    if (!std::cin || (cr != 0 && cr != 1)) {
        std::cout << "Incorrect input\n";
        return 1;
    }
    if (cr == 0) {
        persistent_vector<std::string> v("foo.data", 0, "");
        // skip to the end of line...
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        for (;;) {
            std::string line;
            std::cout << "Enter a string to add to the vector (empty string to end program)\n";
            std::getline(std::cin, line);
            if (line.empty()) break;
            v.data().push_back(line);
        }
    }
    else {
        persistent_vector<std::string> v("foo.data");
        for (const std::string& i : v.data()) {
            std::cout << i << '\n';
        }
    }
    return 0;
}

CodePudding user response:

When a programmer creates a vector class, he must ensure that the resources acquired for that vector are released when they are no longer needed. (See RAII)

C Reference : https://en.cppreference.com/w/cpp/language/raii

Wikipedia : https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization

Stack Overflow : What is meant by Resource Acquisition is Initialization (RAII)?

Microsoft : https://docs.microsoft.com/en-us/cpp/cpp/object-lifetime-and-resource-management-modern-cpp?view=msvc-170

Before the program closes, all resources must be released. (No leaking resources, memory included)

It is not possible to create a vector class that does not delete its contents after closing a program. Secure operating systems will release program resources when the program is closed.

If you want the program not to lose customer information after closing, you need to save the information in persistent (non-volatile) storage device, such as a disk.

As CinCout, 김선달, Serge Ballesta say, you have to save the customer information to a file, and write the program so that you can read that file during the start of the program.

#include <iostream>
#include <fstream>
#include <string>
#include <vector>

struct customer {

    std::string name;
    int balance;
    int password;

};

int main() {
    
    std::vector <customer> customers;
    std::ifstream ifs("info.txt");
    {

        customer customer{};

        while (ifs >> customer.name >> customer.balance >> customer.password)
            customers.push_back(customer);

    }

    for (const auto& [name, balance, password] : customers) {

        std::cout <<
            "\nName     : " << name     <<
            "\nBalance  : " << balance  <<
            "\nPassword : " << password <<
            '\n';

    }



    std::cout << "\n\nWelcome\n\n";

    std::ofstream ofs("info.txt", std::ios_base::app);

    char cont{};

    do {

        customer customer{};

        std::cout << "Name     : ";
        std::cin >> customer.name;

        std::cout << "Balance  : ";
        std::cin >> customer.balance;

        std::cout << "Password : ";
        std::cin >> customer.password;

        ofs << customer.name << ' ' << customer.balance << ' ' << customer.password << '\n';

        std::cout << "Add another customer? (Y/N) : ";
        std::cin >> cont;

    } while (cont == 'Y');



    for (const auto& [name, balance, password] : customers) {

        std::cout <<
            "\nName     : " << name     <<
            "\nBalance  : " << balance  <<
            "\nPassword : " << password <<
            '\n';

    }

}

CPlusPlus : https://www.cplusplus.com/doc/tutorial/files/

LearnCpp : https://www.learncpp.com/cpp-tutorial/basic-file-io/

(About File I/O)

This program is a prototype, I left some things incomplete (like check readings, user-defined I/O operators, duplicate code, formatting, reallocations of customers, ifs is not required after range-for structured binding,...).

I suggest you read the book "Programming: Principles and Practice Using C ", I’m reading it and it helped me a lot.

(I’m also a beginner)

Edit: I also suggest you use "using namespace std;" only for small projects, examples or simple exercises. Do not use "using namespace std;" for real projects, large projects or projects that may include other dependencies because the use of "using namespace std;" could lead to a possible naming collisions between names within std and the names of other codes and libraries.

It’s not good practice to use it all the time.

  • Related