i have these code for save a structure data to a file and then read it:

struct user
{
    string name;
    image foto;
    string adress;
    int age;
};

user usrName={"joaquim",image("C:\\Nova pasta\\acrobat.bmp"), "viseu",32};
user usrName2;

FILE* f = fopen("C:\\Nova pasta\\username1.dat", "w+b");
    if(f==NULL)
        DebugText("error");
    fwrite(&usrName, sizeof( user), 1, f);
    fseek(f, 0, SEEK_SET);
    fread(&usrName2, sizeof(user), 1, f);
    fclose(f);

    img=usrName2.foto;

only when i end the program, i get, sometimes, a memory leak.
what you can tell me?
(image is my image class, for working with images)

Recommended Answers

All 24 Replies

If f==NULL, your program still keep going through fwrite()...

You cannot write an std::string to a file like that. You also cannot write the image structure to a file like that unless it is a POD structure. std::strings are allocated on the heap internally (usually) and contain constructors and all sorts of internal book keeping.

You also cannot READ back an std::string or image like that. It will 100% crash.

Consider:

class string
{
private:
    char* internalMemory; //imagine this is at 0x800000
    unsigned int size;

public:
    string(const char* str)
    {
        this->size = strlen(str);
        this->internalMemory = new char[this->size + 1];
        strcpy(internalMemory, str);
    }

    ~string()
    {
        delete[] internalMemory;
    }
};

int main()
{
    string str{"Test"};
    fwrite(..., &str, .....);
}

The class allocates on the heap and destroys the memory in the destructor. If you were to write this to a file the way you are doing now, you'd be writing:

0x800000
100

Then when you read it back you'd be reading back:

0x800000
100

However, there is no memory allocated at 0x800000 when you read the string back. You're reading in a POINTER ADDRESS not the data that is pointed to by the pointer.

This is undefined behaviour because the destructor will call "delete" on non-existent memory or memory that isn't yours.

You need to serialize the string and the image properly!

triumphost: i'm sorry, but i can read the file. my problem is, only, when i close\ends the program

@cambalinho I can guarantee you cannot read the file. You absolutely CANNOT write an std::string to the file like you are doing above. Especially using C functions like you are in your post.

Try this:

Write to the file like you are doing above.
Close the program.
Read the file that you just wrote above.

Does it read? Does it crash when the program is finished reading?

triumphost: the error only happens when i close\ends the program.
now i use C++ code, it's more stable.
i can use the string.
but i have my image class: have a HBITMAP object. now i don't get any error, unless i use my image class. can you explain better?

struct user
{
    string name="";
    string adress="";
    image foto;
    int age=0;

};

user usrName[2];
user usrName2[2];

template<typename structure>
void SaveDataBase(string filename,structure &StructureVariable )
{
    remove(filename.c_str());
    ofstream writefile;
    writefile.open(filename.c_str(), ios::out | ios::binary);
    writefile.write ((char *)&StructureVariable,sizeof(structure));
    writefile.close();
}

template<typename structure>
void ReadDataBase(string filename,structure &StructureVariable )
{
    ifstream readfile;
    readfile.open(filename.c_str(), ios::out | ios::binary);
    readfile.read ((char*)&StructureVariable,sizeof(structure));
    readfile.close();
}
//using it:
    usrName[0].adress="viseu";
    usrName[0].age=23;
    usrName[0].name="joaquim";
    usrName[0].foto.FileName="C:\\Nova pasta\\acrobat.bmp";
    usrName[1].adress="viseu2";
    usrName[1].age=233;
    usrName[1].name="joaquim2";
    usrName[1].foto.FileName="C:\\Nova pasta\\acrobat.bmp";

    remove("C:\\Nova pasta\\username1.dat");
    SaveDataBase("C:\\Nova pasta\\username1.dat",usrName);
    ReadDataBase("C:\\Nova pasta\\username1.dat",usrName2);

when i close\ends the program, i get the error. if i take of the image object, no error happens.
heres the image error: https://onedrive.live.com/?id=C3EF456E15C8DEB6!1299&cid=C3EF456E15C8DEB6&group=0&parId=C3EF456E15C8DEB6!197&o=OneUp
these is a Windows message. so i only can show you: 'the program stops working\responding'

Example:

#include <iostream>
#include <fstream>
#include <cstring>

struct image
{
    unsigned char* pixels;
    unsigned int width, height;

    image(unsigned char* pixels, unsigned int width, unsigned int height)
    {
        this->width = width;
        this->height = height;
        this->pixels = new unsigned char[width * height * 4];

        memcpy(this->pixels, pixels, width * height * 4);
    }

    ~image()
    {
        delete[] pixels;

        this->pixels = NULL;
        this->width = 0;
        this->height = 0;
    }
};

struct user
{
    std::string name="";
    std::string address="";
    image foto;
    int age=0;
};


void writeUser(user &usr)
{
    std::ofstream file("C:/Users/Brandon/Desktop/data.dat", std::ios::out | std::ios::binary);

    std::size_t size = usr.name.size();
    file.write(reinterpret_cast<char*>(&size), sizeof(size));
    file.write(&usr.name[0], size);

    size = usr.address.size();
    file.write(reinterpret_cast<char*>(&size), sizeof(size));
    file.write(&usr.address[0], size);

    file.write(reinterpret_cast<char*>(&usr.foto.width), sizeof(usr.foto.width));
    file.write(reinterpret_cast<char*>(&usr.foto.height), sizeof(usr.foto.height));
    file.write(reinterpret_cast<char*>(&usr.foto.pixels[0]), usr.foto.width * usr.foto.height * 4);

    file.write(reinterpret_cast<char*>(&usr.age), sizeof(usr.age));
}

void readUser(user &usr)
{
    std::ifstream file("C:/Users/Brandon/Desktop/data.dat", std::ios::in | std::ios::binary);

    std::size_t size = 0;
    file.read(reinterpret_cast<char*>(&size), sizeof(size));
    usr.name.resize(size);
    file.read(&usr.name[0], size);

    size = 0;
    file.read(reinterpret_cast<char*>(&size), sizeof(size));
    usr.address.resize(size);
    file.read(&usr.address[0], size);

    unsigned char* pixels = NULL;
    unsigned int width = 0, height = 0;
    file.read(reinterpret_cast<char*>(&width), sizeof(width));
    file.read(reinterpret_cast<char*>(&height), sizeof(height));

    pixels = new unsigned char[width * height * 4];
    file.read(reinterpret_cast<char*>(&pixels[0]), width * height * 4);
    usr.foto = image(pixels, width, height);

    file.read(reinterpret_cast<char*>(&usr.age), sizeof(usr.age));
}

i'm sorry triumphost, but how can i overloading ofstream and ifstream?

friend ofstream &operator << (ofstream &f, const image &obj)
    {
        f<<obj.HBitmap <<obj.imageweight << obj.imageheight<<obj.img;
        return f;
    }

    friend ifstream &operator >> (ifstream &f, const image &obj)
    {
        f>>obj.HBitmap >>obj.imageweight >> obj.imageheight>>obj.img;
        return f;
    }

error message: "cannot bind 'std::basic_istream<char>' lvalue to 'std::basic_istream<char>&&'"

You cannot write an HBITMAP to a file. You need to write the pixels contained within the HBITMAP to the file instead. HBITMAP is just a void pointer (void*). If you attempt to write it to the file, it will just write the address to the file and not the image itself. Otherwise you need to reinterpret_cast<const char*>(obj.hBmp).

Example:

std::ofstream& operator << (std::ofstream &os, const image &img)
{
    os.write(reinterpret_cast<const char*>(img.hBmp), sizeof(HBITMAP));
    os << img.width << img.height;
    return os;
}

std::ifstream& operator << (std::ifstream &is, image &img)
{

    is.read(reinterpret_cast<char*>(img.hBmp), sizeof(HBITMAP));
    is >> img.width >> img.height;
    return is;
}

You can write the pixels instead like so:

std::ofstream& operator << (std::ofstream &os, const image &img)
{
    os.write(reinterpret_cast<const char*>(&img.width), sizeof(img.width));
    os.write(reinterpret_cast<const char*>(&img.height), sizeof(img.height));
    os.write(reinterpret_cast<const char*>(&img.pixels), img.width * img.height * 4);
    return os;
}

OR:

std::ofstream& operator << (std::ofstream &os, const image &img)
{
    os << img.width << img.height;
    os.write(reinterpret_cast<const char*>(&img.pixels), img.width * img.height * 4);
    return os;
}

from your 1st code i get these error:
"'std::ofstream& image::operator<<(std::ofstream&, const image&)' must take exactly one argument"
why?

@cambalinho, because you're trying to put that into the class itself. The above operator requires friend access.

true.. now i have miss something that i don't know :(
these functions aren't completed, but they miss something that i don't know:

friend ofstream& operator << (ofstream &os, const image &img2)
    {
        os << img2.imageweight << img2.imageheight << img2.strfilename;
        os.write(reinterpret_cast<const char*>(img2.hbmMask), sizeof(HBITMAP));
        os.write(reinterpret_cast<const char*>(img2.img), sizeof(Image));

        return os;
    }

    friend ifstream& operator << (ifstream &is, image &img2)
    {
        if(img2.isimgused==false)
            img2.isimgused==true;
        if(img2.isGDIPLUSIniciated==false)
        {
            Gdiplus::GdiplusStartup(&img2.m_gdiplusToken, &img2.gdiplusStartupInput, NULL);
            img2.isGDIPLUSIniciated=true;
        }
        is >> img2.imageweight >> img2.imageheight >> img2.strfilename ;
        is.read(reinterpret_cast<char*>(img2.hbmMask), sizeof(HBITMAP));
        img2.readimagefile(img2.strfilename);
        return is;
    }

the problem continues even test it with readimagefile() function. the HBITMAP is returned without the problem. the problem is when i close the aplication :(

see just in these way:

friend ofstream& operator << (ofstream &os, const image &img2)
    {
        os << img2.strfilename;
        return os;
    }

    friend ifstream& operator << (ifstream &is, image &img2)
    {
        if(img2.isGDIPLUSIniciated==false)
        {
            Gdiplus::GdiplusStartup(&img2.m_gdiplusToken, &img2.gdiplusStartupInput, NULL);
            img2.isGDIPLUSIniciated=true;
        }
        is >> img2.strfilename ;
        img2.readimagefile(img2.strfilename);
        return is;
    }

like you see i only save the string file name(just testing). the image is showed, but when i closes, the problem continues

@cambalinho, don't write pointers to the file.. You CANNOT write HBITMAP to a file. You CANNOT write hbmMask to the file! That is why the problem continues.

You MUST convert the HBITMAP to pixels, write the sizes then the pixels. Then when you read it back, you must read the sizes, then the pixels, and then turn it back into an HBITMAP.

---

no escriba punteros al archivo .. no se puede escribir HBITMAP en un archivo. No se puede escribir hbmMask al archivo ! Por eso, el problema continúa .

Debe convertir el HBITMAP a píxeles , escriben los tamaños entonces los píxeles. Entonces, cuando usted lee de nuevo , usted debe leer los tamaños a continuación, los píxeles , y luego convertirlo de nuevo en un HBITMAP .

---

#include <iostream>
#include <stdexcept>
#include <vector>
#include <cstring>
#include <memory>
#include <windows.h>

HBITMAP HBITMAPFromPixels(const std::vector<std::uint8_t> &Pixels, std::uint32_t width, std::uint32_t height, std::uint16_t BitsPerPixel)
{
    BITMAPINFO Info = {0};
    std::memset(&Info, 0, sizeof(BITMAPINFO));

    Info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    Info.bmiHeader.biWidth = width;
    Info.bmiHeader.biHeight = -height;
    Info.bmiHeader.biPlanes = 1;
    Info.bmiHeader.biBitCount = BitsPerPixel;
    Info.bmiHeader.biCompression = BI_RGB;
    Info.bmiHeader.biSizeImage = ((width * BitsPerPixel + 31) / 32) * 4 * height;

    HDC dc = GetDC(nullptr);
    HBITMAP hBmp = CreateDIBitmap(dc, &Info.bmiHeader, CBM_INIT, &Pixels[0], &Info, DIB_RGB_COLORS);
   ReleaseDC(nullptr, dc);
   return hBmp;
}

void HBITMAPToPixels(HBITMAP BitmapHandle, std::vector<std::uint8_t> &Pixels, std::uint32_t &width, std::uint32_t &height, std::uint16_t &BitsPerPixel)
{
    if (BitmapHandle == nullptr)
    {
        throw std::logic_error("Null Pointer Exception. BitmapHandle is Null.");
    }

    Pixels.clear();
    BITMAP Bmp = {0};
    BITMAPINFO Info = {0};
    HDC DC = CreateCompatibleDC(nullptr);
    std::memset(&Info, 0, sizeof(BITMAPINFO));
    HBITMAP OldBitmap = (HBITMAP)SelectObject(DC, BitmapHandle);
    GetObject(BitmapHandle, sizeof(Bmp), &Bmp);

    Info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    Info.bmiHeader.biWidth = width = Bmp.bmWidth;
    Info.bmiHeader.biHeight = height = Bmp.bmHeight;
    Info.bmiHeader.biPlanes = 1;
    Info.bmiHeader.biBitCount = BitsPerPixel = Bmp.bmBitsPixel;
    Info.bmiHeader.biCompression = BI_RGB;
    Info.bmiHeader.biSizeImage = ((width * Bmp.bmBitsPixel + 31) / 32) * 4 * height;

    Pixels.resize(Info.bmiHeader.biSizeImage);
    GetDIBits(DC, BitmapHandle, 0, height, &Pixels[0], &Info, DIB_RGB_COLORS);
    SelectObject(DC, OldBitmap);
    height = height < 0 ? -height : height;
    DeleteDC(DC);
}


int main()
{
      HBITMAP hbmMask = .....;

      std::ofstream file("foo.dat", std::ios::binary);

      if (file.is_open())
      {
           std::vector<std::uint8_t> pixels;
           std::uint32_t width, height;
           std::uint16_t bpp;

           HBITMAPToPixels(pixels, width, height, bpp);

           file << width;
           file << height;
           file << bpp;
           file.write(reinterpret_cast<const char*>(&pixels[0]), width * height * (bpp / 8));
           file.close();
      }

      std::ifstream ifs("foo.dat", std::ios::binary);
      if (ifs.is_open())
      {
            DeleteObject(hbmMask);

            std::vector<std::uint8_t> pixels;
            std::uint32_t width, height;
            std::uint16_t bpp;

            file >> width;
            file >> height;
            file >> bpp;
            pixels.resize(width * height * (bpp / 8));

            file.read(reinterpret_cast<char*>(&pixels[0]), pixels.size());
            file.close();

            hbmMask = HBITMAPFromPixels(pixels, width, height, bpp);
      }

      ...
      ...

      DeleteObject(hbmMask);
}

thanks for that triumphost.
now i need another correction :(
i can overloading the operator >> and <<. but can i overloading the read() and write()?
i need overloading these operator for just use the object name for write\read it on file

You can't overload fstream's write unless you inherit from it, OR you create a stream class that wraps it.

i have news :)
now i overload the string ostream and istream:

std::ostream& operator << (std::ostream& lhs, const string& rhs)
{
    int stringsize=rhs.size();
    lhs<<stringsize;
    lhs.write(reinterpret_cast< const char*>(&rhs),rhs.size());
    return lhs;
}

std::istream& operator >> (std::istream& lhs, string& rhs)
{
    string chrfilename;
    int stringsize;
    lhs>>stringsize;
    lhs.read(reinterpret_cast<char*>(&chrfilename), stringsize);
    rhs=chrfilename;
    return lhs;
}

but string have them, but it's limited. i mean it will read until space ' '... using these overloading we can read a entire string.
i need ask anotherthing:
- using your code, i can overloading for HBITMAP;
- but i don't know how i will do it for Image GDIPLUS :(
we have the Save() method with IStream but it's diferent from ostream and istream, right?

Your above code is incorrect. You never resized the string! You are also not writing the string to the file properly. The below is the correct way to do it.

std::ostream& operator << (std::ostream& lhs, const string& rhs)
{
    int stringsize=rhs.size();
    lhs<<stringsize;
    lhs.write(rhs.c_str(), rhs.size());
    return lhs;
}

std::istream& operator >> (std::istream& lhs, string& rhs)
{
    int stringsize;
    lhs>>stringsize;
    rhs.resize(stringsize);
    lhs.read(&rhs[0], stringsize);
    return lhs;
}

You can write the GDIPlus::Image by getting its HBitmap or its pixels.

Gdiplus::BitmapData info;
Gdiplus::Rect rect(0, 0, bmWidth, bmHeight );
image->LockBits(&rect, Gdiplus::ImageLockModeRead, pixel_format, &info);

std::vector<unsigned char> pixels;
pixels.resize(bmWidth * bmHeight * 4);

memcpy(&pixels[0], info.Scan0, pixels.size());
image->UnlockBits(&info);

file << bmWidth;
file << bmHeight;
file << 4;
file.write(reinterpret_cast<char*>(&pixels[0]), bmWidth * bmHeight * 4);

i'm sorry, but your correction have a memory leak.
"You can write the GDIPlus::Image by getting its HBitmap or its pixels."
for static images. but not animated gif's. that's why i need write\read them in stream way:

friend std::ostream& operator << (std::ostream& lhs, const image& rhs)
    {
        if(IfFileExists(rhs.strfilename)==true)
            lhs<<rhs.strfilename;
        else
        {
            IStream* pIStream1 = NULL;
            CreateStreamOnHGlobal(NULL,FALSE,&pIStream1);
            CLSID pngClsid;
            GetEncoderClsid(L"image/gif", &pngClsid);
            rhs.img->Save(pIStream1,&pngClsid,NULL);
            lhs<< pIStream1;
        }
        return lhs;
    }


    friend std::istream& operator >> (std::istream& lhs, image& rhs)
    {

        lhs>>rhs.strfilename;
        if(IfFileExists(rhs.strfilename)==true)
            rhs.readimagefile(rhs.strfilename);//FileName it's a property
        else
        {
            IStream* pIStream1 = NULL;

            lhs>> (char*)pIStream1;
            rhs.img->FromStream(pIStream1,FALSE);
        }
        return lhs;
    }

but i get a memory leak :(

Yeah because you are leaking it. You specify FALSE to CreateStreamOnHGlobal and never free the stream or memory.

My correction uses an std::vector which does not leak. My correction does not release the image for you because it does not own it or know where it comes from. That's up to you to do.

You really need to stop trying to write pointers to files. You CANNOT do lhs << pStream;

I'm not sure how many times I can say that :( pStream is a pointer. You cannot write pointers to a file.

If you prefer your way then:

STATSTG stats = {0};
IStream* pStream = nullptr;
CLSID pngClsid;

CreateStreamOnHGlobal(nullptr, TRUE, &pIStream);
GetEncoderClsid(L"image/gif", &pngClsid);
rhs.img->Save(pIStream, &pngClsid, nullptr);

pStream->Stat(&stats, 0);

ULONG dwRead = 0;
std::size_t size = pStream.cbSize.QuadPart;
std::vector<unsigned char> pixels;
pixels.resize(size);

pStream->Read(&pixels[0], size, &dwRead);
pStream->Release();

lhs.write(reinterpret_cast<const char*>(&size), sizeof(size));
lhs.write(reinterpret_cast<const char*>(&pixels[0]), size);

//......

std::size_t size = 0;
std::vector<unsigned char> pixels;
IStream *pStream = nullptr;
ULONG dwWritten = 0;
LARGE_INTEGER li;
li.QuadPart = 0;

file.read(reinterpret_cast<char*>(&size), sizeof(size));
pixels.resize(size);

file.read(reinterpret_cast<char*>(&pixels[0]), size);

CreateStreamOnHGlobal(nullptr, TRUE, &pStream);
pStream->Write(&pixels[0], size, &dwWritten);
pStream->Seek(li, STREAM_SEEK_SET, nullptr);
pixels = std::vector<unsigned char>();

rhs.img->FromStream(pStream, FALSE);
pStream->Release();

error:

pStream->cbSize.QuadPart

error: 'IStream' has no member named 'cbSize'|

how can i get IStream size?

triumphost: i had found some errors on your code.. i fix them, but i don't get any results :(

friend std::ostream& operator << (std::ostream& lhs, const image& rhs)
    {
        STATSTG stats = {0};
        IStream* pIStream = nullptr;
        CLSID pngClsid;
        CreateStreamOnHGlobal(nullptr, TRUE, &pIStream);
        GetEncoderClsid(L"image/gif", &pngClsid);
        rhs.img->Save(pIStream, &pngClsid, nullptr);
        pIStream->Stat(&stats, 0);
        ULONG dwRead = 0;
        STATSTG stInformation;
        std::size_t size = stats.cbSize.QuadPart;
        std::vector<unsigned char> pixels;
        pixels.resize(size);
        pIStream->Read(&pixels[0], size, &dwRead);
        pIStream->Release();
        lhs.write(reinterpret_cast<const char*>(&size), sizeof(size));
        lhs.write(reinterpret_cast<const char*>(&pixels[0]), size);
        return lhs;
    }


    friend std::istream& operator >> (std::istream& lhs, image& rhs)
    {   

        std::size_t size = 0;
        std::vector<unsigned char> pixels;
        IStream *pStream = nullptr;
        ULONG dwWritten = 0;
        LARGE_INTEGER li;
        li.QuadPart = 0;
        lhs.read(reinterpret_cast<char*>(&size), sizeof(size));
        pixels.resize(size);
        lhs.read(reinterpret_cast<char*>(&pixels[0]), size);
        CreateStreamOnHGlobal(nullptr, TRUE, &pStream);
        pStream->Write(&pixels[0], size, &dwWritten);
        pStream->Seek(li, STREAM_SEEK_SET, nullptr);
        pixels = std::vector<unsigned char>();
        rhs.img->FromStream(pStream, FALSE);
        pStream->Release();
        return lhs;
    }

i don't get any results :(

hi bros
can i know the code of applications that are run in c++ and others,?

Bold Text Herehi bros
can i know the code of applications that are run in c++ and others,?

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.