我正在编写一个 C++ websocket 服务器库。在我提供的示例之一中,我使用了两个类 session_base
和 session
.我这样做是为了获得 tcp::socket
session_base
中的对象父类在将对它的引用传递给 ws::session<tcp::socket>
之前初始化(使用移动构造函数)存储此引用供以后使用的父类。我创建 ws:session 作为模板类的原因是我可以使用 boost::asio::ssl::stream
s 以及 tcp 套接字。
tcp::socket
是否有效?反对 session
的成员类,将对此未初始化对象的引用传递给 ws::session
构造函数(尚未使用 tcp::socket
- 仅存储引用)然后初始化 tcp::socket
对象之后使用套接字移动构造函数?
当前代码:
using boost::asio::ip::tcp;
class session_base {
public:
session_base(tcp::socket socket) : socket_(std::move(socket)) { }
protected:
tcp::socket socket_;
};
using T = tcp::socket;
class session : public session_base, public ws::session<T> {
public:
session(tcp::socket socket) :
session_base(std::move(socket)), ws::session<T>(socket_)
{
std::cout << "session()\n";
}
~session() {
std::cout << "~session()\n";
}
private:
void on_open() override {
std::cout << "WebSocket connection open\n";
}
void on_msg(const ws::message &msg) override {
/* Do stuff with msg */
read();
}
void on_close() override {
std::cout << "WebSocket connection closed\n";
}
void on_error() override {
std::cout << "WebSocket connection error\n";
}
};
建议代码:
下面建议的代码对我有用,但我想知道这是定义的行为并推荐。
using boost::asio::ip::tcp;
using T = tcp::socket;
class session : public ws::session<T> {
public:
session(tcp::socket socket) :
ws::session<T>(socket_), socket_(std::move(socket))
{
std::cout << "session()\n";
}
~session() {
std::cout << "~session()\n";
}
private:
tcp::socket socket_;
void on_open() override {
std::cout << "WebSocket connection open\n";
}
void on_msg(const ws::message &msg) override {
/* Do stuff with msg */
read();
}
void on_close() override {
std::cout << "WebSocket connection closed\n";
}
void on_error() override {
std::cout << "WebSocket connection error\n";
}
};
最佳答案
如果 ws::session
构造函数仅存储对套接字的引用但不使用该引用来调用套接字成员函数或访问数据成员,则程序是良构的.该标准将此称为对 3.8/6 ([basic.life/6]) 中分配存储的引用:
Similarly, before the lifetime of an object has started but after the storage which the object will occupy has been allocated or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any glvalue that refers to the original object may be used but only in limited ways. For an object under construction or destruction, see 12.7. Otherwise, such a glvalue refers to allocated storage (3.7.4.2), and using the properties of the glvalue that do not depend on its value is well-defined. The program has undefined behavior if:
— an lvalue-to-rvalue conversion (4.1) is applied to such a glvalue,
— the glvalue is used to access a non-static data member or call a non-static member function of the object, or
— the glvalue is implicitly converted (4.10) to a reference to a base class type, or
— the glvalue is used as the operand of a
static_cast
(5.2.9) except when the conversion is ultimately to cvchar&
or cvunsigned char&
, or— the glvalue is used as the operand of a
dynamic_cast
(5.2.7) or as the operand oftypeid
.
请注意,必须在获取引用时分配存储,调用session
构造函数时也是如此。
但尽管如此,我还是不推荐这种方法。主要是因为在 ws::session
构造函数中很容易忘记传递的引用引用了一个尚未初始化的对象,并在以后引入错误。最好使用 base-from-member idiom并保留您的原始代码。
关于c++ - 将对未初始化对象的引用传递给父类(super class)构造函数,然后用它的移动构造函数初始化所述对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34477383/