I get a warning C4355: 'this' : used in base member initializer list from Visual C++ 2010:
I have a class holding a handle, and I want to automatically close the handle even if the ctor for the class fails (so its dtor is not called). However, I don't want to bother making a whole handle-wrapping class, and would rather hold it in a smart pointer. And so I wrote this:
foo.h
~~~~~
class Foo
{
...
Log &_log;
std::unique_ptr<void, std::function<void (void *)>> _handle;
...
}
foo.cpp
~~~~~~~
#include <windows.h>
Foo::Foo(Log &lg, ...) : _log(lg), ... _handle(nullptr, [&](void *h){ if (h) { if (!CloseHandle(h)) LOG(_log, "Could not close port: " << LastWinErr()); h = nullptr; } })
{
HANDLE h(CreateFile( ...
if (h == ...
_handle.reset(h);
... // Bunch of other stuff that could potentially throw
}
Previously to the closure I was initializing _handle with something like _handle(nullptr, bind(PortDeleter, placeholders::_1, ref(_log))), but that requires a separate definition.
My questions: is the warning a concern for this specific instance? Either way, what is the detailed reason? Is there a trivial way to avoid it?
The short is, if you pass your this pointer around and it's used to access member functions or variables in the initializer list or in the destructor, Bad Things Happen™. If you know that isn't going to happen, then feel free to ignore the warning. Of course, it's also a good warning- if any of the functions or variables that you access in the destructor belong to the class, then this is unsafe, as you may be accessing them prior to their construction/after their destruction. The problem is not critical if you know your initialization/destruction orders, but generally a bad move as this makes maintenance rather fiddly at best. As you could capture the constructor parameter instead, I'd have to recommend that.
Related
Here is the code:
class SomeType {
public:
SomeType() {}
~SomeType() {}
std::string xxx;
}
bool funtion_ab() {
SomeType(); // This is a right val;
// The right val destructs here when I test the code. I want to make sure that it would always destructs here.
int a = 0, b = 10;
....// other code
return true;
}
Please tell me if you know the truth. Thank you!
What you have is called a temporary object. From §6.7.7,
Temporary objects are created
when a prvalue is converted to an xvalue
or, more specifically,
[Note 3: Temporary objects are materialized:
...
when a prvalue that has type other than cv void appears as a discarded-value expression ([expr.context]).
— end note]
and, on the lifetime, the same section has this to say
Temporary objects are destroyed as the last step in evaluating the full-expression ([intro.execution]) that (lexically) contains the point where they were created.
You can read more about the expression semantics, but in your case "full-expression" is fairly unambiguous.
SomeType();
The "full-expression" containing your constructor call is... the constructor call itself. So the destructor will be called immediately after evaluating the constructor. There are some exceptions to this rule (such as if the temporary object is thrown as an exception or is bound as a reference), but none of those apply here.
As noted in the comments, compilers are free to inline your constructor and destructor calls and then are free to notice that they do nothing and omit them entirely. Optimizers can do fun stuff with your code, provided it doesn't change the semantics. But a strict reading of the standard states that the destructor is called exactly where you suggested.
I can't understand the function move in c++11.
From here, I got things below:
Although note that -in the standard library- moving implies that the
moved-from object is left in a valid but unspecified state. Which
means that, after such an operation, the value of the moved-from
object should only be destroyed or assigned a new value; accessing it
otherwise yields an unspecified value.
In my opinion, after move(), the moved-from object has been "clear". However, I've done a test below:
std::string str = "abcd";
std::move(str);
std::cout<<str;
I got abcd on my screen.
So has the str been destroyed? If so, I could get abcd because I'm just lucky? Or I misunderstood the function move?
Besides, when I read C++ Primer, I got such a code:
class Base{/* ... */};
class D: public Base{
public:
D(D&& d): Base(std::move(d)){/* use d to initialize the members of D */}
};
I'm confused now. If the function move will clear the object, the parameter d will be clear, how could we "use d to initialize the members of D"?
std::move doesn't actually do anything. It's roughly analogous to a cast expression, in that the return value is the original object, but treated differently.
More precisely, std::move returns the object in a form which is amenable to its resources being 'stolen' for some other purpose. The original object remains valid, more or less (you're only supposed to do certain special things to it, though that's primarily a matter of convention and not necessarily applicable to non-standard-library objects), but the stolen-away resources no longer belong to it, and generally won't be referenced by it any more.
But! std::move doesn't, itself, do the stealing. It just sets things up for stealing to be allowed. Since you're not doing anything with the result, let alone something which could take advantage of the opportunity, nothing gets stolen.
std::move doesn’t move anything. std::move is merely a function template that perform casts. std::move unconditionally casts its argument to an rvalue,
std::move(str);
With this expression you are just doing type cast from lvalue to rvalue.
small modification in program to understand better.
std::string str = "abcd";
std::string str1 = std::move(str);
std::cout<<str<<std::endl;
std::cout<<str1<<std::endl;
str lvalue typecast to rvalue by std::move, std::string = std::move(str); =>this expression call the string move constructor where actual stealing of resources take placed. str resources(abcd) are steeled and printed empty string.
Here is sample implementation of move function. Please note that it is not complete implementation of standard library.
template<typename T> // C++14; still in
decltype(auto) move(T&& param) // namespace std
{
using ReturnType = remove_reference_t<T>&&;
return static_cast<ReturnType>(param);
}
Applying std::move to an object tells the compiler that the object is eligible to be moved from. It cast to the rvalue.
class Base{/* ... */};
class D: public Base{
public:
D(D&& d): Base(std::move(d)){/* use d to initialize the members of D */}
};
Base(std::move(d)) it will do up-casting only move the base class part only.
Here one more interesting thing to learn for you. If you do not invoke base class destructor with std::move like D(D&& d): Base(d) then d will be considered as lvalue and copy constructor of Base class involved instead of move constructor. Refer for more detail Move constructor on derived object
I've some code that moves an object into another object. I won't need the original, moved object anymore in the upper level. Thus move is the right choice I think.
However, thinking about safety I wonder if there is a way to invalidate the moved object and thus preventing undefined behaviour if someone accesses it.
Here is a nice example:
// move example
#include <utility> // std::move
#include <vector> // std::vector
#include <string> // std::string
int main () {
std::string foo = "foo-string";
std::string bar = "bar-string";
std::vector<std::string> myvector;
myvector.push_back (foo); // copies
myvector.push_back (std::move(bar)); // moves
return 0;
}
The description says:
The first call to myvector.push_back copies the value of foo into the
vector (foo keeps the value it had before the call). The second call
moves the value of bar into the vector. This transfers its content
into the vector (while bar loses its value, and now is in a valid but
unspecified state).
Is there a way to invalidate bar, such that access to it will cause a compiler error? Something like:
myvector.push_back (std::move(bar)); // moves
invalidate(bar); //something like bar.end() will then result in a compiler error
Edit: And if there is no such thing, why?
Accessing the moved object is not undefined behavior. The moved object is still a valid object, and the program may very well want to continue using said object. For example,
template< typename T >
void swap_by_move(T &a, T &b)
{
using std::move;
T c = move(b);
b = move(a);
a = move(c);
}
The bigger picture answer is because moving or not moving is a decision made at runtime, and giving a compile-time error is a decision made at compile time.
foo(bar); // foo might move or not
bar.baz(); // compile time error or not?
It's not going to work.. you can approximate in compile time analysis, but then it's going to be really difficult for developers to either not get an error or making anything useful in order to keep a valid program or the developer has to make annoying and fragile annotations on functions called to promise not to move the argument.
To put it a different way, you are asking about having a compile time error if you use an integer variable that contains the value 42. Or if you use a pointer that contains a null pointer value. You might be succcessful in implementing an approximate build-time code convention checker using clang the analysis API, however, working on the CFG of the C++ AST and erroring out if you can't prove that std::move has not been called till a given use of a variable.
Move semantics works like that so you get an object in any it's correct state. Correct state means that all fields have correct value, and all internal invariants are still good. That was done because after move you don't actually care about contents of moved object, but stuff like resource management, assignments and destructors should work OK.
All STL classes (and all classed with default move constructor/assignment) just swap it's content with new one, so both states are correct, and it's very easy to implement, fast, and convinient enough.
You can define your class that has isValid field that's generally true and on move (i. e. in move constructor / move assignment) sets that to false. Then your object will have correct state I am invalid. Just don't forget to check it where needed (destructor, assignment etc).
That isValid field can be either one pointer having null value. The point is: you know, that object is in predictable state after move, not just random bytes in memory.
Edit: example of String:
class String {
public:
string data;
private:
bool m_isValid;
public:
String(string const& b): data(b.data), isValid(true) {}
String(String &&b): data(move(b.data)) {
b.m_isValid = false;
}
String const& operator =(String &&b) {
data = move(b.data);
b.m_isValid = false;
return &this;
}
bool isValid() {
return m_isValid;
}
}
It is my understanding that move semantics can use move-constructors to elide what would otherwise be a copy. For example, a function returning a (perhaps) large data structure can now return by value, and the move constructor will be used to avoid a copy.
My question is this: is the compiler required to not copy when this is possible? It doesn't seem to be the case. In that case, wouldn't the following code have "implementation-defined" semantics?
static const int INVALID_HANDLE = 0xFFFFFFFF;
class HandleHolder {
int m_handle;
public:
explicit HandleHolder(int handle) : m_handle(handle) {}
HandleHolder(HandleHolder& hh) {
m_handle = hh.m_handle;
}
HandleHolder(HandleHolder&& hh) : m_handle(INVALID_HANDLE) {
swap(m_handle, hh.m_handle);
}
~HandleHolder() noexcept {
if (m_handle != INVALID_HANDLE) {
destroy_the_handle_object(m_handle);
}
}
};
Say then we make a function:
HandleHolder make_hh(int handle) { return HandleHolder(handle); }
Which constructor is called? I would expect the move constructor, but am I guaranteed the move constructor?
I'm aware this is a silly example and that -- for example -- the copy constructor of this object should be deleted because there is no way to use it safely otherwise, but the semantics are simple enough that I wouldn't think something like this would be implementation-defined.
Yes, of course. There's nothing implementation-defined about it.
If there is a move constructor and it can be used, and it is a choice between a move constructor and a copy constructor, the move constructor will be invoked. That is a guarantee.
[C++11: 13.3.3.2/3]: [..] Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if:
[..]
S1 and S2 are reference bindings (8.5.3) and neither refers to an implicit object parameter of a non-static member function declared without a ref-qualifier, and S1 binds an rvalue reference to an rvalue and S2 binds an lvalue reference.
[..]
I think your confusion stems from misuse of the term "elide". The compiler may elide copies/moves and replace them with nothingness — with in-place construction that bypasses the invocation of a constructor altogether. Copy elision never results in a move, and move elision never results in a copy. Either the object "transferral" happens or it does not.
You could sort of argue that your program has "implementation-defined" semantics in the sense that you don't know whether copies/moves will be elided until the program has been compiled, and because such elision is allowed to modify side-effects (such as console output). But we don't tend to think of it that way.
Regardless, this does not affect which of the copy and move constructors will be invoked if either are to be.
Your example is further flawed because only your move constructor can be invoked: your copy constructor takes a ref-to-non-const which can't be bound through an rvalue initialiser.
I am trying to use a FILE pointer multiple times through out my application
for this I though I create a function and pass the pointer through that. Basically I have this bit of code
FILE* fp;
_wfopen_s (&fp, L"ftest.txt", L"r");
_setmode (_fileno(fp), _O_U8TEXT);
wifstream file(fp);
which is repeated and now instead I want to have something like this:
wifstream file(SetFilePointer(L"ftest.txt",L"r"));
....
wofstream output(SetFilePointer(L"flist.txt",L"w"));
and for the function :
FILE* SetFilePointer(const wchar_t* filePath, const wchar_t * openMode)
{
shared_ptr<FILE> fp = make_shared<FILE>();
_wfopen_s (fp.get(), L"ftest.txt", L"r");
_setmode (_fileno(fp.get()), _O_U8TEXT);
return fp.get();
}
this doesn't simply work. I tried using &*fp instead of fp.get() but still no luck.
You aren't supposed to create FILE instances with new and destroy them with delete, like make_shared does. Instead, FILEs are created with fopen (or in this case, _wfopen_s) and destroyed with fclose. These functions do the allocating and deallocating internally using some unspecified means.
Note that _wfopen_s does not take a pointer but a pointer to pointer - it changes the pointer you gave it to point to the new FILE object it allocates. You cannot get the address of the pointer contained in shared_ptr to form a pointer-to-pointer to it, and this is a very good thing - it would horribly break the ownership semantics of shared_ptr and lead to memory leaks or worse.
However, you can use shared_ptr to manage arbitrary "handle"-like types, as it can take a custom deleter object or function:
FILE* tmp;
shared_ptr<FILE> fp;
if(_wfopen_s(&tmp, L"ftest.txt", L"r") == 0) {
// Note that we use the shared_ptr constructor, not make_shared
fp = shared_ptr<FILE>(tmp, std::fclose);
} else {
// Remember to handle errors somehow!
}
Please do take a look at the link #KerrekSB gave, it covers this same idea with more detail.