When i try to create my shader with CreateVertexShader(), I get COM error 'The paremeter is incorrect.'.
struct ShaderData
{
LPVOID ShaderCode;
size_t ShaderSize;
};
This function works but it leaks. When delete[] buffer is uncommented I get the error.
Shader::ShaderData Shader::LoadShader(const std::string& file)
{
std::ifstream ifs(file, std::ios::in | std::ios::binary);
if (!ifs) return;
ifs.seekg(0, std::ios::end);
size_t size = static_cast<std::size_t>(ifs.tellg());
ifs.seekg(0, std::ios::beg);
char* buffer = new char[size];
ifs.read(buffer, len);
ShaderData data = { buffer, size };
//delete[] buffer;
return data;
}
Another version of the same function but using std::vector, I still get the same error.
Shader::ShaderData Shader::LoadShader(const std::string& file)
{
std::ifstream ifs(file, std::ios::in | std::ios::binary);
if (!ifs) return;
ifs.seekg(0, std::ios::end);
size_t size = static_cast<std::size_t>(ifs.tellg());
ifs.seekg(0, std::ios::beg);
std::vector<char> buffer(size);
ifs.read(buffer.data(), size);
ShaderData data = { static_cast<void*>(buffer.data()), size };
return data;
}
Function creating the shaders. m_vertex_data and m_pixel_data are both member variables of class Shader, and holds the data returned from LoadShader().
void Shader::CreateShaders(ID3D11Device* device)
{
device->CreateVertexShader(m_vertex_data.ShaderCode,
m_vertex_data.ShaderSize,
nullptr,
m_vertex_shader.GetAddressOf()));
device->CreatePixelShader(m_pixel_data.ShaderCode,
m_pixel_data.ShaderSize,
nullptr,
m_pixel_shader.GetAddressOf()));
}
You need to keep the buffer pointed to by ShaderData::ShaderCode; valid until you create a shader. To avoid leaks just replace it with ::std::vector< char > ShaderCode; so the buffer will be kept safe. Actually you don't need ShaderData struct at all, just return a vector containing shader code.
Related
The function is to extract the file contents into a vector as below:
std::vector<uint8_t> GetFileContents(const std::string& filename)
{
std::ifstream file(filename, std::ios::binary);
if (!file.good())
{
return {};
}
file.seekg(0, std::ios::end);
std::streampos fileSize = file.tellg();
file.seekg(0, std::ios::beg);
std::vector<uint8_t> fileData(fileSize);
file.read((char*) &fileData[0], fileSize);
return fileData;
}
On the lines:
std::vector<uint8_t> fileData(fileSize);
file.read((char*) &fileData[0], fileSize);
return fileData;
The fileData vector is copied into a temporary vector to be returned here?
Do I need to change to:
std::vector<uint8_t> fileData(fileSize);
file.read((char*) &fileData[0], fileSize);
return std::move(fileData);
to do a move and save a vector copy operation?
Any other changes required in the function to support move?
Is there any value in std::move({}) for the empty case?
No, you shouldn't use std::move there.
That avoids possible NRVO, and there is an implicit move anyway.
See Automatic_move_from_local_variables_and_parameters for further detail.
I am trying to write a char* to a binary file.
This is what I have now.
void Write(char* fileName, char* pData)
{
ofstream binFile (fileName, ios::out | ios::binary);
if (binFile.open())
{
binFile.write((char*)&pData, sizeof(pData));
binFile.close();
}
}
void Read(char* fileName, char* pData)
{
ifstream binFile(fileName, ios::in | ios::binary);
if(binFile.open())
{
binFile.read(char*)&pData, sizeof(pData));
binFile.close
}
}
int main()
{
char* testData = "ABCdEFG"; // not real data
char* getTestData;
char* file = "C:\\testData.dat";
Write(file, testData);
Read(file, getTestData);
}
Test data will be of unknown length. May not always be the same.
When i run the program once, and write and read. I can get back the test data.
But when i stop the program and run it again, this time without writing. Just reading, i cannot get back the test data.
I don't really understand whats happening here.
Can some one explain it to me?
binFile.write((char*)&pData, sizeof(pData));
is wrong. It just writes the value of the pointer. It does not write the data.
You need to use:
binFile.write(pData, strlen(pData));
However, that won't be adequate to read the data back. To be able to read the data back, you'll need to write the size of the string first.
size_t len = strlen(pData);
binFile.write((char*)&len, sizeof(len));
binFile.write(pData, len);
And when reading the data back, you will need to use:
size_t len = 0;
binFile.read(char*)&len, sizeof(len));
binFile.read(pData, len);
and then, null terminate the string.
pData[len] = '\0';
PS
Make sure getTestData is properly initialized before using it to read the data.
char getTestData[100];
will be adequate for your test case.
Update
You can make your program a bit better by using std::string instead of char*. The size of the saved data can be more easily managed when a std::string is used.
void Write(std::string const& fileName, std::string const& data)
{
std::ofstream binFile(fileName, std::ios::out | std::ios::binary);
if (binFile.is_open())
{
size_t len = data.size();
binFile.write((char*)&len, sizeof(len));
binFile.write((char*)&data[0], len);
// No need. The file will be closed when the function returns.
// binFile.close();
}
}
void Read(std::string const& fileName, std::string& data)
{
std::ifstream binFile(fileName, std::ios::in | std::ios::binary);
if(binFile.is_open())
{
size_t len = 0;
binFile.read((char*)&len, sizeof(len));
data.resize(len);
binFile.read((char*)&data[0], len);
}
}
int main()
{
std::string file = "testData.dat";
std::string testData = "ABCdEFG";
Write(file, testData);
std::string getTestData;
Read(file, getTestData);
std::cout << getTestData << std::endl;
}
I am trying to write a char* to a binary file.
This is what I have now.
void Write(char* fileName, char* pData)
{
ofstream binFile (fileName, ios::out | ios::binary);
if (binFile.open())
{
binFile.write((char*)&pData, sizeof(pData));
binFile.close();
}
}
void Read(char* fileName, char* pData)
{
ifstream binFile(fileName, ios::in | ios::binary);
if(binFile.open())
{
binFile.read(char*)&pData, sizeof(pData));
binFile.close
}
}
int main()
{
char* testData = "ABCdEFG"; // not real data
char* getTestData;
char* file = "C:\\testData.dat";
Write(file, testData);
Read(file, getTestData);
}
Test data will be of unknown length. May not always be the same.
When i run the program once, and write and read. I can get back the test data.
But when i stop the program and run it again, this time without writing. Just reading, i cannot get back the test data.
I don't really understand whats happening here.
Can some one explain it to me?
binFile.write((char*)&pData, sizeof(pData));
is wrong. It just writes the value of the pointer. It does not write the data.
You need to use:
binFile.write(pData, strlen(pData));
However, that won't be adequate to read the data back. To be able to read the data back, you'll need to write the size of the string first.
size_t len = strlen(pData);
binFile.write((char*)&len, sizeof(len));
binFile.write(pData, len);
And when reading the data back, you will need to use:
size_t len = 0;
binFile.read(char*)&len, sizeof(len));
binFile.read(pData, len);
and then, null terminate the string.
pData[len] = '\0';
PS
Make sure getTestData is properly initialized before using it to read the data.
char getTestData[100];
will be adequate for your test case.
Update
You can make your program a bit better by using std::string instead of char*. The size of the saved data can be more easily managed when a std::string is used.
void Write(std::string const& fileName, std::string const& data)
{
std::ofstream binFile(fileName, std::ios::out | std::ios::binary);
if (binFile.is_open())
{
size_t len = data.size();
binFile.write((char*)&len, sizeof(len));
binFile.write((char*)&data[0], len);
// No need. The file will be closed when the function returns.
// binFile.close();
}
}
void Read(std::string const& fileName, std::string& data)
{
std::ifstream binFile(fileName, std::ios::in | std::ios::binary);
if(binFile.is_open())
{
size_t len = 0;
binFile.read((char*)&len, sizeof(len));
data.resize(len);
binFile.read((char*)&data[0], len);
}
}
int main()
{
std::string file = "testData.dat";
std::string testData = "ABCdEFG";
Write(file, testData);
std::string getTestData;
Read(file, getTestData);
std::cout << getTestData << std::endl;
}
How can i access the data from a buffer?
int WINAPI mRecv( SOCKET s, char *buf, int len, int flags ) {
// Code to access the data from buffer
}
You are probably looking for std::istream::read. It is used to extract characters from stream.
And if you want to iterate over the data then you can use the std::istreambuf_iterator
std::string
getBufferContent(const std::string& path)
{
std::ifstream file(path);
std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
return content;
}
Which one of the following would be the most efficient and why? I'm leaning towards the unique_ptr because I think that there is no copy being done when returning the data read. It's just a transfer of ownership of a pointer.
For example, I think that the string version would create a temporary string, read data into that, and upon returning, it'd copy its data into the assigned result?
However, I'm not sure that I'm right. Any ideas what I mean and which is the best?
UniquePtr:
std::unique_ptr<const char[]> ReadFile(const char* FileName)
{
std::fstream file(FileName, std::ios::in);
if (file.is_open())
{
file.seekg(0, std::ios::end);
std::size_t size = file.tellg();
std::unique_ptr<char[]> result(new char[size]);
file.seekg(0, std::ios::beg);
file.read(result.get(), size);
file.close();
return std::move(result);
}
return nullptr;
}
Vector:
std::string ReadFile(const char* FileName)
{
std::fstream file(FileName, std::ios::in);
if (file.is_open())
{
file.seekg(0, std::ios::end);
std::vector<std::int8_t> buffer(file.tellg());
file.seekg(0, std::ios::beg);
file.read(result.data(), result.size());
file.close();
return std::string(result.data());
}
return std::string();
}
String:
std::string ReadFile(const char* FileName)
{
std::fstream file(FileName, std::ios::in);
if (file.is_open())
{
std::string result = std::string();
file.seekg(0, std::ios::end);
result.resize(file.tellg());
file.seekg(0, std::ios::beg);
file.read(&result[0], result.size());
file.close();
return result;
}
return std::string();
}
std::string ReadFile(const char* FileName)
{
std::fstream file(FileName, std::ios::in);
std::string result = std::string();
if (file.is_open())
{
file.seekg(0, std::ios::end);
result.resize(file.tellg());
file.seekg(0, std::ios::beg);
file.read(&result[0], result.size());
file.close();
}
return result;
}
I have no proof , but if function has only one return , copy elision might be implemented by compiler , if there are 2 returns inside function ,
copy elision might not work as expected ~~~
The
return std::string(result.data());
will only work if the data is null-terminated.
Apart from that complication it needlessly copies from a vector to a string.
The std::string code is most natural for reading text (text mode open of file).
You won't see much of a performance difference since the file i/o dwarfs the rest, but anyway with C++03 you will most likely get Return Value Optimization (depends on compiler), and with C++11 you will get move optimization of the result if you just use std::move.