C++私有char成员分配失败的表达式必须是可修改的LValk
我试图创建一个简单的异常类,但我遇到了这个恼人的问题,不知道出了什么问题。请注意,我是C++ NoOB,因此尝试学习如何使用新而不是MALOC。 代码如下:C++私有char成员分配失败的表达式必须是可修改的LValk,c++,arrays,linux,new-operator,C++,Arrays,Linux,New Operator,我试图创建一个简单的异常类,但我遇到了这个恼人的问题,不知道出了什么问题。请注意,我是C++ NoOB,因此尝试学习如何使用新而不是MALOC。 代码如下: #include <errno.h> #include <exception> #include <string.h> /** * An exception describing a failure in creating a socket. */ class SocketCreationExcep
#include <errno.h>
#include <exception>
#include <string.h>
/**
* An exception describing a failure in creating a socket.
*/
class SocketCreationException : public std::exception
{
private:
char *msg;
public:
~SocketCreationException()
{
delete msg;
}
const char *what() const throw()
{
const char *str = "Socket creation failure:";
char *err = strerror(errno);
msg = new char[strlen(str) + strlen(err) + 1]; // Error here
return msg;
}
};
编辑:
很多很棒的答案和提示!谢谢大家的帮助!这真的很有用 成员函数是const限定的。因此,它无法更改成员的值 在实践中,异常应该在其构造函数中初始化其消息,并且只返回一个指向已在其构造函数中构造的消息的指针 此外,errno可能已被某些操作覆盖。您应该将抛出表达式中的值作为参数传递给异常的构造函数 此外,该类是可复制的,但在复制时会导致未定义的行为 此外,如果您的程序编译了多次,那么它会泄漏内存。此外,您从不在分配的内存中存储任何内容 您可能应该继承std::runtime_error,它有一个接受消息的构造函数,因此您不需要自己实现存储消息,这在异常情况下实际上是非常棘手的 我是C++ NoOB,因此尝试着学习如何使用新的 这不是一个您应该使用new的用例,事实上,这样的用例非常罕见。如果std::runtime_错误继承不是一个更好的选择,那么您应该使用std::string,您不应该在异常情况下直接使用它,因为复制可能会引发错误,但在其他情况下,这是非常好的 下面是一个正确的例子:
class SocketCreationException : public std::runtime_error
{
public:
SocketCreationException(int number)
: std::runtime_error(message(number));
{}
private:
std::string message(int number)
{
return "Socket creation failure: "s
+ std::strerror(number);
}
};
// usage (immediately after operation that set errno)
int number = errno;
if (number)
throw SocketCreationException(errno);
编辑:我忘记了std::system\u错误,这正是这个用例的错误,请参阅答案。成员函数是const限定的。因此,它无法更改成员的值 在实践中,异常应该在其构造函数中初始化其消息,并且只返回一个指向已在其构造函数中构造的消息的指针 此外,errno可能已被某些操作覆盖。您应该将抛出表达式中的值作为参数传递给异常的构造函数 此外,该类是可复制的,但在复制时会导致未定义的行为 此外,如果您的程序编译了多次,那么它会泄漏内存。此外,您从不在分配的内存中存储任何内容 您可能应该继承std::runtime_error,它有一个接受消息的构造函数,因此您不需要自己实现存储消息,这在异常情况下实际上是非常棘手的 我是C++ NoOB,因此尝试着学习如何使用新的 这不是一个您应该使用new的用例,事实上,这样的用例非常罕见。如果std::runtime_错误继承不是一个更好的选择,那么您应该使用std::string,您不应该在异常情况下直接使用它,因为复制可能会引发错误,但在其他情况下,这是非常好的 下面是一个正确的例子:
class SocketCreationException : public std::runtime_error
{
public:
SocketCreationException(int number)
: std::runtime_error(message(number));
{}
private:
std::string message(int number)
{
return "Socket creation failure: "s
+ std::strerror(number);
}
};
// usage (immediately after operation that set errno)
int number = errno;
if (number)
throw SocketCreationException(errno);
编辑:我忘记了std::system\u错误,这正是这个用例的错误,请参阅答案
这是一个常量类方法,这就是const关键字的意思
msg = new char[strlen(str) + strlen(err) + 1]; // Error here
这将尝试修改msg类成员。因为这是一个常量类方法,所以不能这样做
所示代码中还有三个基本错误:
调用两次会泄漏内存
由于构造函数从不将msg初始化为任何内容,而析构函数将删除它,因此不会调用将导致内存损坏和可能崩溃的内容。由于没有复制构造函数,复制一个对象会在某个点上导致双重删除,并导致另一次崩溃
显示的代码是用于存储消息的char数组,但实际上从未将其设置为任何值。返回的字符串将是完整的和垃圾总数
您必须解决所有这些问题,才能使自定义异常对象正常工作
解决所有内存损坏的最简单方法是,首先不要手动分配内存
请注意,我是C++ NoOB,因此尝试学习如何使用新的
而不是malloc
<>现代C++代码很少需要新的或删除任何东西。当然,理解内存分配是C++的基础,但很少需要实际使用它。在本例中,std::string执行此处所需的所有操作。因此,使用std::string代替。不需要析构函数。无需自行获得100%正确的内存分配。您的std::字符串将为您完成此操作
为了能够修改const class方法中的class方法,只需将其声明为mutable
这比计算和跟踪每个单独的字符以及正确实现内存分配逻辑要容易得多
这是一个常量类方法,这就是const keywo
rd的意思是
这将尝试修改msg类成员。因为这是一个常量类方法,所以不能这样做
所示代码中还有三个基本错误:
调用两次会泄漏内存
由于构造函数从不将msg初始化为任何内容,而析构函数将删除它,因此不会调用将导致内存损坏和可能崩溃的内容。由于没有复制构造函数,复制一个对象会在某个点上导致双重删除,并导致另一次崩溃
显示的代码是用于存储消息的char数组,但实际上从未将其设置为任何值。返回的字符串将是完整的和垃圾总数
您必须解决所有这些问题,才能使自定义异常对象正常工作
解决所有内存损坏的最简单方法是,首先不要手动分配内存
请注意,我是C++ NoOB,因此尝试学习如何使用新的
而不是malloc
<>现代C++代码很少需要新的或删除任何东西。当然,理解内存分配是C++的基础,但很少需要实际使用它。在本例中,std::string执行此处所需的所有操作。因此,使用std::string代替。不需要析构函数。无需自行获得100%正确的内存分配。您的std::字符串将为您完成此操作
为了能够修改const class方法中的class方法,只需将其声明为mutable
这比必须计算和跟踪每个单独的字符,并正确实现内存分配逻辑要容易得多。除了在其他答案中所说的,实际上不需要在这里声明自定义异常类。你已经可以做你想做的了。例如,您可以执行以下操作:
throw std::system_error(errno, std::generic_category(), "Socket creation failure");
除了在其他答案中所说的之外,实际上不需要在这里声明自定义异常类。你已经可以做你想做的了。例如,您可以执行以下操作:
throw std::system_error(errno, std::generic_category(), "Socket creation failure");
什么是const-qualified。它不能修改成员变量。作为一种可能的解决方法,请改为在构造函数中创建字符串。我真的建议您将errno作为参数传递给该构造函数。否则,您不知道错误和调用what函数之间会发生什么,errno的值是不确定的,除非前面的函数失败。哦,还要使用std::string。@catata不要在这里使用新字符[]。使用std::string存储消息,并让what返回msg.c_str。您还可以使用一个已内置此功能的异常作为基础:@CataCata your's welcome。但这并不是专门针对错误代码。将任何基本算术类型转换为字符串。你可能也会觉得有趣。你可能想在你的构造函数中接受它而不是int。代码中也出现了一个新的问题,因为在C++ 11中丢弃了Spice,并且从内存中删除了C++ 20中的C++。这是错误的逻辑!大多数用户不需要编写new或delete、malloc或free,因为标准库提供了容器,可以在RAII接口后面安全地抽象出所有底层内容。不要编写代码来使用某个特性;如果您真正需要某个功能,请使用它。你可能不需要新的。什么是const-qualified。它不能修改成员变量。作为一种可能的解决方法,请改为在构造函数中创建字符串。我真的建议您将errno作为参数传递给该构造函数。否则,您不知道错误和调用what函数之间会发生什么,errno的值是不确定的,除非前面的函数失败。哦,还要使用std::string。@catata不要在这里使用新字符[]。使用std::string存储消息,并让what返回msg.c_str。您还可以使用一个已内置此功能的异常作为基础:@CataCata your's welcome。但这并不是专门针对错误代码。将任何基本算术类型转换为字符串。你可能也会觉得有趣。你可能想在你的构造函数中接受它而不是int。代码中也出现了一个新的问题,因为在C++ 11中丢弃了Spice,并且从内存中删除了C++ 20中的C++。这是错误的逻辑!大多数用户不需要编写new或delete、malloc或free,因为标准库提供了容器,可以在RAII接口后面安全地抽象出所有底层内容。不要编写代码来使用某个特性;如果您真正需要某个功能,请使用它。你可能不需要新的。