Why is there no std::protect?
Well, I'm not aware of why it wasn't implemented. Perhaps it wasn't proposed, or perhaps there were some subtle gotchas.
That said, I think you can write it pretty easily
template<typename T>
struct protect_wrapper : T
{
protect_wrapper(const T& t) : T(t)
{
}
protect_wrapper(T&& t) : T(std::move(t))
{
}
};
template<typename T>
typename std::enable_if< !std::is_bind_expression< typename std::decay<T>::type >::value,
T&& >::type
protect(T&& t)
{
return std::forward<T>(t);
}
template<typename T>
typename std::enable_if< std::is_bind_expression< typename std::decay<T>::type >::value,
protect_wrapper<typename std::decay<T>::type > >::type
protect(T&& t)
{
return protect_wrapper<typename std::decay<T>::type >(std::forward<T>(t));
}
The two versions of protect are so that non-bind expressions are not wrapped (they just pass through). Everything else is passed by move/copy to the protect_wrapper
, which simply inherits from the type. This allows the type's functions to pass through, or for it to convert to the type.
It makes a copy/move however, so it can be safely used with rvals. And since it only protects types that are bind_expressions, it minimizes the amount of copying that has to occur.
int main()
{
//// Ok, with protect
auto bind_expr =
std::bind<int>(invoke_with_42{}
, protect(std::bind(&add, 1, std::placeholders::_1)));
std:: cout << bind_expr() << std::endl;
return 0;
}
Why the constructor of std::ostream is protected?
I'll admit that I don't understand it either. I can't find any
default constructor at all for std::istream
, and I would think
you would want one if you want to create a bidirectional stream,
because of the strange way std::ios_base
works: the
constructor does not initialize anything, but the derived
class must call std::ios_base::init
explicitly in its
constructor. When multiple inheritance is involved (i.e.
bidirectional IO, where the class derives from both std::istream
and std::ostream
), I would expect only the most
derived class to call std::ios_base::init
. (Instd::iostream
, std::ios_base::init
will be called twice.)
In fact, before looking it up in the standard, I was about to
answer that the default constructor was protected, because it
didn't call std::ios_base::init
, and using it directly, rather
than in a derived class, would result in an uninitialized
stream.
Anyhow, your immediate problem has a simple solution:
std::ostream out( NULL );
Also: the function you need to set up its sink later is the
non-const version of rdbuf()
, not copyfmt()
. rdbuf()
is
used to read and to set the pointer to the streambuf
,copyfmt()
copies the formatting flags, but does not touch
the pointer to streambuf
.
So you can do things like:
std::ostream out( NULL );
// ...
std::filebuf fileBuffer;
if ( filenameGiven ) {
fileBuffer.open( filename.c_str(), std::ios_base::out );
}
if ( fileIsOpen() ) {
out.rdbuf( &fileBuffer );
} else {
out.rdbuf( std::cout.rdbuf() );
}
(I do this a lot. In fact, I thought that it was the usual
idiom when you didn't know up front whether to output to a file
or to std::cout
.)
EDIT:
And yet another correction: the non-const version of rdbuf
calls clear()
,
so you don't have to. (I knew I'd done this without calling clear()
, but
when I saw that init
set badbit
...)
Anyhow: the summary is: it's usually preferrable to pass a pointer to a valid
streambuf to the constructor of std::ostream
, but if you can't, it's
perfectly valid to pass a null pointer, and set a valid pointer later usingrdbuf()
. And the answers which say otherwise are simply wrong.
Problem with declaring a protected pointer to a vector
The problem wasn't the c++ code itself, but the framework it used, in this case ROOT. If you define a pointer in a ROOT class, you have to tell the program what to do with that pointer in the case of the class being written to file. Even though the class might never be written to a file (like in my case).
In this specific case (class never being written to a file), you can simply tell ROOT to ignore the given pointer by adding //!
after the declaration, e.g. write
protected:
std::vector<CustomClass> *mypointer; //!
Thanks to everyone for helping in this helpless case!
Move constructor with protection for non-default-constructible class
You could do the locking in a helper function:
class C {
A a;
std::mutex m; // using a standard mutex instead
A A_mover(C&& other) {
std::lock_guard<std::mutex> lock(other.m);
return std::move(other.a); // move into a temporary while locked
}
public:
C() = delete;
C(int _k) : a{_k}, m{} {}
C(C&& other) : a(A_mover(std::move(other))), m{} {}
};
If C
itself is composed of multiple fields, move the mutex out to a wrapper class. The wrapper should ideally keep only one object + a mutex. This uses your Mutex
as it seems the standard std::mutex
isn't available.
class C {
A a;
A b;
public:
C() = delete;
C(int _k, int _l) : a{_k}, b{_l} {}
C(C&& other) = default;
};
class CLocker {
public:
template<typename...Args>
CLocker(Args...args) : c(std::forward<Args>(args)...) {}
CLocker(CLocker&& other) : c(mover(std::move(other))) {}
private:
struct MutexLockGuard {
MutexLockGuard(Mutex& M) : m(M) { m.take(); }
~MutexLockGuard() { m.give(); }
Mutex& m;
};
C mover(CLocker&& other) {
MutexLockGuard lock(m);
return std::move(other.c); // move into a temporary while locked
}
C c;
Mutex m;
};
int main() {
CLocker cl1(10, 20);
CLocker cl2(std::move(cl1));
}
Finally an option without a wrapper suggested by @Jarod42:
class MutexLockGuard {
public:
MutexLockGuard(Mutex& M) : m(M) { m.take(); }
~MutexLockGuard() { m.give(); }
private:
Mutex& m;
};
class C {
public:
C() = delete;
C(int _k, int _l) : a{_k}, b{_l}, m{} {}
C(C&& other) : C(MutexLockGuard(other.m), std::move(other)) {}
//^ delegate to protected constructor
protected:
C(MutexLockGuard, C&& other) : // do the moves while the lock is held
a{std::move(other.a)},
b{std::move(other.b)},
m{}
{}
private:
A a;
A b;
Mutex m;
};
Related Topics
Adding Static Libcurl to Code::Blocks Ide
How to Declare Constexpr Class in a Header and Define It in a Separate .Cpp File
Attribute & Reflection Libraries for C++
Gcc: Difference Between -O3 and -Os
Compile Openmp Programs with Gcc Compiler on Os X Yosemite
Segfaults in Malloc() and Malloc_Consolidate()
How to Use Const in Vectors to Allow Adding Elements, But Not Modifications to the Already Added
Constructor Initialization VS Assignment
Comma Operator in If Condition
Deciphering C++ Template Error Messages
Comparing 3 Modern C++ Ways to Convert Integral Values to Strings
How to Rotate a N X N Matrix by 90 Degrees
Std::Forward_List and Std::Forward_List::Push_Back
Win32: How to Hide 3Rd Party Windows in Taskbar by Hwnd
How to Convert a Command-Line Argument to Int
Qobject: Cannot Create Children for a Parent That Is in a Different Thread