void Employee::store_data(string filename) {
fstream file;
file.open(filename,ios::app | ios::binary);
if (file) {
file.write((char*)&this,sizeof(this));
file.close();
}
else cout<<"\n Error in Opening the file!";
}
this is what i tried.
I want to store the current object of employee class to a file in binary mode.
but i get this this
error: lvalue required as unary '&' operand
file.write((char*)&this,sizeof(this));
this isn't an actual variable, so you can't take its address. But it already is a pointer, so you don't need to. It also has size of a pointer, so your sizeof is wrong. And then in C++ you should not use C-style casts. So fixing these 3 things, your line becomes
file.write(reinterpret_cast<char*>(this), sizeof(*this));
That should compile.
However, note that if Employee contains anything complex, such as std::string member variables, pointer member variables, virtual methods, constructor / destructor etc, you can't read the data back. That write doesn't in that case write everything, or writes wrong runtime values, and you get garbage back. You enter the dreaded Undefined Behavior territory, anything can happen (including things apparently working when you test it).
The language does not allow use of &this as an expression since (https://timsong-cpp.github.io/cppwp/n3337/class.this#1)
the keyword this is a prvalue expression
You can use the addressof (&) operator only on lvalue expressions.
More importantly, you need to use
file.write(reinterpret_cast<char const*>(this), sizeof(*this));
to save the object.
Related
I'm coding c++11.
In a class A, I have a member variable "member" which is defined as
vector<OtherClass> member; // A's member variable
I would like to serialize A ( so I want to all the data type in OtherClass contained in the vector ) into file in binary format so I defined a function write as follows.
void A::write(ostream& os){ // A's function for outputting A
os.write(reinterpret_cast<const char*>( &(member.size()) ), sizeof(member.size()));
}
But compiler said lvalue required as unary '&' operand.
How can I fix it without creating a temporary object such as long size=member.size() in the write function?
The problem is &(member.size()) - you're not assigning size()'s return value and trying to take the address of it (it may not even have an address).
But no idea why you're calling size here anyway you need the start address of the actual data: member.data() (or if you dont have C++11 &member[0])
"How can I fix it without creating a temporary object"
You can't. You want to use &, which takes the address of an object. No object, no address. It's really that simple.
Note that your long size = member.size() idea doesn't create a temporary variable. That's an ordinary variable.
This may sound like a strange question, but am I safe in defining operator<< or operator>> for a FILE object, or would I be violating potential clauses in the C or C++ standards, or can it possibly cause other issues?
(Yes, I do know about C++ I/O streams. I'm not asking if this is a good idea. I'm asking if it's allowed.)
Example:
#include <stdio.h>
FILE &operator>>(FILE &file, int &d)
{
if (fread(&d, sizeof(d), 1, &file) != 1)
{ throw "I/O error"; }
return file;
}
int main()
{
int x;
FILE *file = fopen("File.bin", "rb");
*file >> x;
fclose(file);
return x;
}
Ignoring, for the moment, the question of whether this is a good idea (but it's not), it's open to question whether this is truly allowed.
The C++ standard defines all the relevant headers and functions--<cstdio> is covered in §27.9.2. If you really wanted to use it, <stdio.h> is even part of the C++ standard (§D.5), though it's officially deprecated.
That would tend to indicate that it's allowed. The wording from the C standard (§7.19.1/2) is:
FILE
which is an object type capable of recording all the information needed to control a
stream, including its file position indicator, a pointer to its associated buffer (if any), an error indicator that records whether a read/write error has occurred, and an end-of-file
indicator that records whether the end of the file has been reached;
The question would be whether a FILE is really required to represent that type directly, or could (for example) be typedefd to void, so (for example) fopen actually returns a void *. The internals of the library that use it would cast it to the proper type, but to the outside world (i.e., your program) it's completely opaque. In particular, if it is a void *, you can't dereference it, not even to just get a reference instead of a pointer.
I'd guess that's mostly theoretical though. I think in general, assuming that FILE is a unique type on which you can do overloading is fairly safe. You shouldn't assume anything about the internals of what it points at, but you're fairly safe assuming you can dereference it to get a reference instead of a pointer (and fairly safe assuming that the overload will be differentiated from overloads on other types such as integers).
I am reading about STL string class. It is mentioned as below
STL string class chooses not to define conversion operators, but rather use the c_str() and data() methods for directly accessing the memory. The STL purposely does not include implicit conversion operators to prevent misuse of raw string pointers.
My question is
c_str() returns const char* pointer and still user can modify string value. Am I right?
What does the author mean by "to prevent misuse of raw string pointers"? Please explain, preferably with an example.
Thanks!
No, you cannot use the return value of std::string::c_str() to
modify the string. Trying to do so is undefined behavior. And
the problem was (and still is) the lifetime of the pointer
returned by std::string::c_str(). It becomes invalid if the
string is destructed, or if any non-const function is called on
the string. The issues are things like:
char const* s = string1 + string2;
// s is invalid here.
vs.
char const* s = (string1 + string2).c_str();
// s is invalid here.
In the first case, it's easy to make the mistake, without
realizing it, so the committee decided to not have implicit
conversion, so that this would be illegal. In the second case,
you have to really want to.
Pointers have always made me blank about the logic I intend to use in code, If someone can help me understand a few concepts that would be really helpful. Here's a code snippet from my program,
vector <char> st;
char *formatForHtml(string str, string htmlTag)
{
string strBegin;
strBegin = "<";
strBegin.append(htmlTag);
strBegin.append(">");
strBegin.append(str);
string strEnd = "</";
strEnd.append(htmlTag);
strEnd.append(">");
strBegin.append(strEnd);
st.resize(strBegin.size());
for (int i =0;i <strBegin.size();i++) {
st[i] = strBegin.at(i);
}
return &st[0];
}
In the code above if I have to return address of st[0], I have to write the function of type char *. I need to know the reason to do so, also if address is the integer value why can I not define function as an int type?
P.S. It's a beginner level doubt.
You don't tell us what st is, so we can't tell whether the code is
totally incorrect, or just bad design. If st is a typo for str
(just guessing, since str isn't used anywhere), then you have
undefined behavior, and the program is incorrect, since you're returning
a pointer into an object which has been destructed. At any rate, a
function like formatForHtml should return an std::string, as a
value, and not a pointer (and certainly not a pointer to a non-const).
I might add that you don't use a loop to copy string values character by
character. std::string acts as a normal value type, so you can just
assign: st = strBegin;.
EDIT:
Just for the record, I've since reexamined your code. The natural way
of writing it would be:
std::string
formatForHtml( std::string const& cdata, std::string const& tag )
{
return '<' + tag + '>' + cdata + "</" + tag + '>';
}
No pointers (at least not visible---in fact, "+ operator), and full use of
std::strings facilities.
I have to write the function of type 'char *' I need to know the reason to do so
There's no reason to do so. Just return a std::string.
From the looks of your code, st is a std::vector<char>. Since std::vector has continuous memory, &st[0] is the address of the first char in the vector, and thus points to the not null-terminated string that the vector represents, which isn't very helpful outside the function because you can't find the length.
That's awkward code, you're expecting 'str' as an argument, but then you return its memory location? Why not return the string itself?
Your code there has a few typos. (Did you mean 'str' when you typed 'st'? If not, then where is 'st' defined?)
As for why you can't define the function as "int" type, that is because an "int" is a different type to "pointer to char".
Personally, I would return 'string', and just have a 'return str' at the end there.
Pointer is pointer, not integer value. Code is right if and only if st is global variable or declared as static in this function. But return string is preferably, than return pointer.
Why don't you use string as return type for your function?
First: a pointer is an adress of something lying in memory, so you can't replace it with an integer (only with some dirty tricks).
Second: &st[0] is the adress of the internal buffer the string uses to store its content. When st goes out of scope (or is reused for the next call), it will be overwritten or given back to the heap manager, so the one calling this function will end with some garbage.
Btw, most of your function does unnessesary work which the string class can do by itself (for example copiing strBegin to st).
Simple.
string str
is something that contains a bunch characters.
str[0]
return the first character.
Therefore,
&str[0]
gives you the address of the first character, therefore it's a "char *" --- "char" being whatever the pointer points to, "*" being the "address of" part of the pointer. The type of the pointer is about the object being pointed to.
Also, addresses may be just "integers" on the hardware level (everything is an integer... except for integers themselves, they are a bunch of bools), but that doesn't mean anything for a higher level language. For a higher level language, a pointer is a pointer, not an integer.
Treating one as another is almost always an error, and C++11 even added the nullptr keyword so we don't have to rely on the one valid "pointer is an integer" case.
And btw, your code won't work. "str" only exists for the duration of the function, so when the function returns "str" ceases to exist, which means the pointer you have returned points into a big black nowhere.
It maybe seems to be a silly question but i really need to clarify this:
Will this bring any danger to my program?
Is the const_cast even needed?
If i change the input pointers values in place will it work safely with std::string or will it create undefined behaviour?
So far the only concern is that this could affect the string "some_text" whenever I modify the input pointer and makes it unusable.
std::string some_text = "Text with some input";
char * input = const_cast<char*>(some_text.c_str());
Thanks for giving me some hints, i would like to avoid the shoot in my own foot
As an example of evil behavior: the interaction with gcc's Copy On Write implementation.
#include <string>
#include <iostream>
int main() {
std::string const original = "Hello, World!";
std::string copy = original;
char* c = const_cast<char*>(copy.c_str());
c[0] = 'J';
std::cout << original << "\n";
}
In action at ideone.
Jello, World!
The issue ? As the name implies, gcc's implementation of std::string uses a ref-counted shared buffer under the cover. When a string is modified, the implementation will neatly check if the buffer is shared at the moment, and if it is, copy it before modifying it, ensuring that other strings sharing this buffer are not affected by the new write (thus the name, copy on write).
Now, with your evil program, you access the shared buffer via a const-method (promising not to modify anything), but you do modify it!
Note that with MSVC's implementation, which does not use Copy On Write, the behavior would be different ("Hello, World!" would be correctly printed).
This is exactly the essence of Undefined Behavior.
To modify an inherently const object by casting away its constness using const_cast is an Undefined Behavior.
string::c_str() returns a const char *, i.e: a pointer to a constant c-style string. Technically, modifying this will result in Undefined Behavior.
Note, that the use of const_cast is when you have a const pointer to a non const data and you wish to modify the non-constant data.
Simply casting will not bring forth an undefined behavior. Modifying the data pointed at, however, will. (Also see ISO 14882:98 5.2.7-7).
If you want a pointer to modifiable data, you can have a
std::vector<char> wtf(str.begin(), str.end());
char* lol= &wtf[0];
The std::string manages it's own memory internally, which is why it returns a pointer to that memory directly as it does with the c_str() function. It makes sure it's constant so that your compiler will warn you if you try to do modifiy it.
Using const_cast in that way literally casts away such safety and is only an arguably acceptable practice if you are absolutely sure that memory will not be modified.
If you can't guarantee this then you must copy the string and use the copy.; it's certainly a lot safer to do this in any event (you can use strcpy).
See the C++ reference website:
const char* c_str ( ) const;
"Generates a null-terminated sequence of characters (c-string) with the same content as the string object and returns it as a pointer to an array of characters.
A terminating null character is automatically appended.
The returned array points to an internal location with the required storage space for this sequence of characters plus its terminating null-character, but the values in this array should not be modified in the program and are only guaranteed to remain unchanged until the next call to a non-constant member function of the string object."
Yes, it will bring danger, because
input points to whatever c_str happens to be right now, but if some_text ever changes or goes away, you'll be left with a pointer that points to garbage. The value of c_str is guaranteed to be valid only as long as the string doesn't change. And even, formally, only if you don't call c_str() on other strings too.
Why do you need to cast away the const? You're not planning on writing to *input, are you? That is a no-no!
This is a very bad thing to do. Check out what std::string::c_str() does and agree with me.
Second, consider why you want a non-const access to the internals of the std::string. Apparently you want to modify the contents, because otherwise you would use a const char pointer. Also you are concerned that you don't want to change the original string. Why not write
std::string input( some_text );
Then you have a std::string that you can mess with without affecting the original, and you have std::string functionality instead of having to work with a raw C++ pointer...
Another spin on this is that it makes code extremely difficult to maintain. Case in point: a few years ago I had to refactor some code containing long functions. The author had written the function signatures to accept const parameters but then was const_casting them within the function to remove the constness. This broke the implied guarantee given by the function and made it very difficult to know whether the parameter has changed or not within the rest of the body of the code.
In short, if you have control over the string and you think you'll need to change it, make it non-const in the first place. If you don't then you'll have to take a copy and work with that.
it is UB.
For example, you can do something like this this:
size_t const size = (sizeof(int) == 4 ? 1024 : 2048);
int arr[size];
without any cast and the comiler will not report an error. But this code is illegal.
The morale is that you need consider action each time.