C++ 小实验 5.8

static std::map<std::ostream *, std::unique_ptr<std::mutex>> stream_locks;
std::ostream& printf_lock(std::ostream& os) {
	auto&ptr= stream_locks[&os];
	if(!ptr)ptr = std::make_unique<std::mutex>();
	ptr->lock();
	return os;
}
std::ostream& printf_unlock(std::ostream& os) {
	auto&ptr= stream_locks[&os];
	ptr->unlock();
	return os;
}

上述程序:实现多进程下有序打印

cout<<printf_lock<<........<<printf_unlock;

上面的auto& ptr换成 auto 报错:换成auto &&可以通过编译且正常运行。



stackoverflow上找到了auto比较好的解释:

auto uses the same mechanism of type deduction as templates, the only exception that I am aware of being that of brace-init lists, which are deduced by auto as std::initializer_list, but non-deduced in a template context.

auto x = expression;

works by first stripping all reference and cv qualifiers from the type of the right hand side expression, then matching the type. For example, if you have const int& f(){...} then auto x = f(); deduces x as int, and not const int&.

The other form,

auto& x = expression

does not strip the cv-qualifiers, so, using the example above, auto& x = f() deduces x as const int&. The other combinations just add cv qualifiers.

If you want your type to be always deduced with cv-ref qualifiers, use the infamous decltype(auto) in C++14, which uses the decltype type deduction rules.

So, in a nutshell, if you want copies, use auto, if you want references, use auto&. Use constwhenever you want additional const-ness.


EDIT There is an additional use case,

auto&& x = expression;

which uses the reference-collapsing rules, same as in the case of forwarding references in template code. If expression is a lvalue, then x is a lvalue reference with the cv-qualifiers of expression. If expression is a rvalue, then x is a rvalue reference.

写的非常清楚,

1. So, in a nutshell, if you want copies, use auto, if you want references, use auto&. Use constwhenever you want additional const-ness.

2.在auto&& x=expression的情况下:If expression is a lvalue, then x is a lvalue reference with the cv-qualifiers of expression. If expression is a rvalue, then x is a rvalue reference.

相信大家看的懂英文,不作翻译这种无用功了。

高票答案:

autoandauto &&cover most of the cases:

  • Useautowhen you need a local copy. This will never produce a reference. The copy (or move) constructor must exist, but it might not get called, due to thecopy elisionoptimization.

  • Useauto &&when you don't care if the object is local or not. Technically, this will always produce a reference, but if the initializer is a temporary (e.g., the function returns by value), it will behave essentially like your own local object.

    Also,auto &&doesn't guarantee that the object will be modifiable, either. Given aconstobject or reference, it will deduceconst. However, modifiability is often assumed, given the specific context.

auto &andauto const &are a little more specific:

  • auto &guarantees that you are sharing the variable with something else. It is always a reference and never to a temporary.

  • auto const &is likeauto &&, but provides read-only access.

注意一句:Useautowhen you need a local copy. This will never produce a reference. The copy (or move) constructor must exist, but it might not get called, due to thecopy elisionoptimization.

基于以上所述:如果使用auto的话,unique_ptr会调用copy ctor,而从错误信息中得知:

‘unique_ptr’ has explicitly marked deleted here

unique_ptr(const unique_ptr&) = delete;

也就是unique_ptr的copy ctor已经被标记为delete了  不能使用;

所以产生call to deleted ctor of ....的错误;

而auto& 和auto&& 都会强制把类型表示为引用,所以不会调用copy ctor 从而解决问题

关于右值引用:https://msdn.microsoft.com/zh-cn/library/dd293668.aspx

第二个问题:

std::ostream& printf_lock(std::ostream& os)换成
std::ostream printf_lock(std::ostream os)

为什么?先看basic_ostream的构造函数

basic_ostream有两个构造函数:
public:
      explicit
      basic_ostream(__streambuf_type* __sb)
      { this->init(__sb); }
protected:
      basic_ostream(){this->init(0);}

同样,&是为了避免构造 。

cout<<1_lock;  //总是打印1 怎么回事?请看下面 摘自stackoverflow

Q

I want to print out a function pointer using cout, and found it did not work. But it worked after I converting the function pointer to (void *), so does printf with %p, such as

#include <iostream>
using namespace std;

int foo() {return 0;}

int main()
{
    int (*pf)();
    pf = foo;
    cout << "cout << pf is " << pf << endl;
    cout << "cout << (void *)pf is " << (void *)pf << endl;
    printf("printf(\"%%p\", pf) is %p\n", pf);
    return 0;
}

I compiled it with g++ and got results like this:

cout << pf is 1
cout << (void *)pf is 0x100000b0c
printf("%p", pf) is 0x100000b0c

So what does cout do with type int (*)()? I was told that the function pointer is treated as bool, is it true? And what does cout do with type (void *)?

Thanks in advance.

EDIT: Anyhow, we can observe the content of a function pointer by converting it into (void *) and print it out using cout. But it does not work for member function pointers and the compiler complains about the illegal conversion. I know that member function pointers is rather a complicated structure other than simple pointers, but how can we observe the content of a member function pointers?

A

There actually is an overload of the << operator that looks something like:

ostream & operator <<( ostream &, const void * );

which does what you expect - outputs in hex. There can be no such standard library overload for function pointers, because are are an infinite number of types of them. So the pointer gets converted to another type, which in this case seems to be a bool - I can't offhand remember the rules for this.

Edit: The C++ Standard specifies:

4.12 Boolean conversions

1 An rvalue of arithmetic, enumeration, pointer, or pointer to member type can be converted to an rvalue of type bool.

This is the only conversion specified for function pointers.

关于cout输出一个输出流可参考:https://zhidao.baidu.com/question/518471065575081725.html?qbl=relate_question_0

附完整程序:

#include <iostream>
#include <chrono>
#include <mutex>
#include <thread>
#include <ostream>
#include <map>

static std::mutex map_lock;
static std::map<std::ostream *, std::unique_ptr<std::mutex>> stream_locks;

std::ostream& 1_lock(std::ostream& os) {
	auto&&p= stream_locks[&os];
	if(!p)p = std::make_unique<std::mutex>();
	p->lock();
	return os;
}

std::ostream& 1_unlock(std::ostream& os) {
	auto&&p= stream_locks[&os];
	p->unlock();
	return os;
}

void locked_outputs(size_t i) {
    std::string str {"Shiyanlou - Contest: Learn by Doing - Log System"};
    std::cout << 1_lock << "Thread " << i << " | 1.1.1.1 - [2018/05/08 00:00:01] \"GET /assets/logo.png HTTP/1.1\" 200" << std::endl << 1_unlock;
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << 1_lock << "Thread " << i << " | 1.1.1.2 - [2018/05/08 00:00:02] \"GET /assets/logo.png HTTP/1.1\" 200" << std::endl << 1_unlock;
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << 1_lock << "Thread " << i << " | 1.1.1.3 - [2018/05/08 00:00:03] \"GET /assets/logo.png HTTP/1.1\" 200" << std::endl << 1_unlock;
    std::cout << 1_lock << "Thread " << i << "---------------------" << std::endl << 1_unlock;
}
int main() {
    std::cout << "Locked output stream" << std::endl;
    std::thread thread1(locked_outputs, 1);
    std::thread thread2(locked_outputs, 2);
    thread1.join();
    thread2.join();
}

觉得有帮助点个赞~

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页