Why Is There No Std::Protect

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. (In
std::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 using
rdbuf(). 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



Leave a reply



Submit