![](/img/trans.png)
[英]C++ - Difference between pointer of a class and object of class in initialization
[英]C++ difference between function declaration and object initialization
如果我写了这行代码:
std::thread t(EchoServer(socket));
编译器如何解释该指令? 它可以是函数声明,也可以只是初始化。 我有followinc代码:
#include <iostream>
#include <thread>
#include <boost/asio.hpp>
#include <boost/asio.hpp>
typedef boost::asio::ip::tcp::socket Socket;
auto socket_deleter = [] (Socket* s) {s->close(); delete s;};
typedef std::unique_ptr<Socket, decltype(socket_deleter)> socket_ptr;
class EchoServer {
public:
static void Listen(unsigned int port)
{
using namespace std;
using namespace boost::asio;
io_service ios;
// create an endpoint to listen to a certain port
ip::tcp::endpoint endpoint(ip::tcp::v4(), port);
cout << "Listening to TCP Socket on port " << port << " ..." << endl;
// Start opening a socket
ip::tcp::acceptor acceptor(ios, endpoint);
// this loop must be infinite... but we accept only 3 connections
auto socket = socket_ptr(new Socket(ios));
std::thread t(EchoServer(socket));
}
EchoServer(socket_ptr&& s) : m_socket(std::move(s))
{
}
void operator ()() const
{
}
private:
socket_ptr m_socket;
};
但是编译器给我以下警告:
C4930: 'std::thread t(EchoServer(socket))': std::thread t(EchoServer(socket)) function not called (was a variable definition intended?).
因此,我该如何解释这一行是std :: thread创建类型的对象,而不是函数声明。
更新1:我使用的Visual Studio 2012不支持统一初始化,因此我将代码从std::thread t((EchoServer(socket)));
更改了std::thread t((EchoServer(socket)));
到std::thread t((EchoServer(socket)));
但是这次我有一个编译时错误,我不明白:
error C2440: '<function-style-cast>': cannot convert from 'std::unique_ptr<_Ty,_Dx>' to 'EchoServer'
我想念什么?
更新2我可能必须了解更好的移动语义,问题是socket_ptr的声明。 我已经以这种(丑陋的)方式更改了代码...但是现在可以编译了。
#include <iostream>
#include <thread>
#include <boost/asio.hpp>
typedef boost::asio::ip::tcp::socket Socket;
auto socket_deleter = [] (Socket* s) {s->close(); delete s;};
/*
typedef std::unique_ptr<Socket, decltype(socket_deleter)> socket_ptr;
*/
typedef Socket* socket_ptr;
class EchoServer {
public:
static void Listen(unsigned int port)
{
using namespace std;
using namespace boost::asio;
io_service ios;
// create an endpoint to listen to a certain port
ip::tcp::endpoint endpoint(ip::tcp::v4(), port);
cout << "Listening to TCP Socket on port " << port << " ..." << endl;
// Start opening a socket
ip::tcp::acceptor acceptor(ios, endpoint);
// this loop must be infinite... but we accept only 3 connections
auto socket = new Socket(ios);
std::thread t((EchoServer(socket)));
}
EchoServer(socket_ptr s) : m_socket(s)
{
}
~EchoServer()
{
m_socket->close();
delete m_socket;
}
void operator ()() const
{
}
private:
socket_ptr m_socket;
};
将Changine socket_ptr用作简单的指针,而不是unique_ptr,此代码有效。
这是一个函数声明。 如果要使用直接初始化声明对象,则可以使用以下方法之一:
std::thread t(EchoServer { socket });
std::thread t { EchoServer(socket) };
std::thread t { EchoServer { socket} };
std::thread t((EchoServer(socket)));
括号初始化无疑是初始化,并且在最后一行中有一个带括号的表达式,该表达式不能用作函数参数声明。
在C ++ 2011中,给定情况下最简单的方法是用大括号替换括号:
std::thread t{EchoServer(socket)};
但是请注意,由于线程既不分离也不联接,因此保证可以调用std::terminate()
。
如您所提到的,该语句有两种可能的解释,但是标准明确规定,在这种歧义的情况下,编译器必须将该语句解释为函数定义(删除多余的括号集):
std::thread t(EchoServer socket);
如果要强制创建std::thread
,则可以添加括号,使该语句不是有效的函数声明:
std::thread t((EchoServer(socket)));
使用不同的语法进行初始化:
std::thread t = std::thread(EchoServer(socket));
或者由于您使用的是C ++ 11,因此可以使用统一初始化 :
std::thread t{EchoServer(socket)};
前两个选项是有效的C ++ 03,但在C ++ 11编译器中,您可能应该使用第三个选项(并且使用std::thread
表示您正在使用C ++ 11功能)
C和C ++编译器在解析时必须建立有关声明和范围的语义知识,并参考该知识以了解如何解析某些内容。
扫描标识符时,可以根据在进行扫描的范围内如何声明该标识符,将其转换为词法类别的令牌。
一个比您更简单的示例是:
A ( B );
这可能是一个函数调用:函数A
的参数是主表达式B
的值。 或者,它可能是名称B
的声明,它将是类型A
的对象。
如果我们的词法分析器能够查看当前作用域中可见的声明,则它可以确定A是类型名称还是将其声明为函数。 然后,它可以将适当种类的令牌传递给解析器,因此适当的短语结构规则将匹配。
static_cast
可用于触发用户定义的转换,因此请尝试
std::thread t(static_cast<EchoServer>(socket));
而不是强制转换的构造函数调用语法。
要解决转换失败的问题,请将构造函数更改为:
EchoServer(socket_ptr&& s) : m_socket(s)
{
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.