首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将unsigned char*转换为const unsigned char*后删除[]

将unsigned char*转换为const unsigned char*后删除[]
EN

Stack Overflow用户
提问于 2013-04-19 16:05:32
回答 3查看 2.4K关注 0票数 8

粗略地说,我有一个包含const unsigned char数组的类。这个类的对象是由一个特殊的工厂函数创建的,该函数还负责构造数组(在堆上)。当在工厂函数中创建一个对象时,它将被赋予指向数组的指针。数组不会被复制,对象只会使用给定的指针。在销毁时,它将释放数组占用的内存块。

代码语言:javascript
复制
class Foo
{
private:
    const unsigned char* array;
    size_t size;

public:
    Foo(const unsigned char* array, size_t size) : array(array), size(size) {}
    ~Foo() {delete [] array;}
};

Foo* factoryFunction(const void* data, size_t size)
{
    unsigned char* array = new unsigned char[size];
    memcpy(array, data, size);
    return new Foo(array, size);
}

现在我想知道是否有任何副作用,因为new []返回unsigned char *,而delete []是为const unsigned char *调用的。不过,我没有得到任何分割错误。

EN

回答 3

Stack Overflow用户

发布于 2013-04-19 16:27:20

这很好,标准中的非标准化文本表明了同样的事情:

[C++11: 5.3.5/2]:如果操作数具有类类型,则通过调用上述转换函数将操作数转换为指针类型,并在本节的其余部分中使用转换后的操作数替换原始操作数。在第一个备选方案(删除对象)中,delete的操作数的值可以是空指针值、指向由先前的new表达式创建的非数组对象的指针、或者指向表示此类对象的基类的子对象(1.8)的指针(第10条)。如果不是,则行为未定义。在第二种选择(删除数组删除delete )中,删除数组的操作数的值可以是空指针值,也可以是由前一个数组删除数组产生的指针值。如果不是,则行为未定义。[注意:这意味着delete-expression的语法必须与new分配的对象类型匹配,而不是与new-expression的语法匹配。-end delete-expression;] [注意:指向常量类型的指针可以是常量类型的操作数。在将指针表达式用作 const -end注意事项的操作数之前,不必丢弃该表达式的常量(5.2.11) ]

以下几段可能会引起争议:

[C++11: 5.3.5/3]:在第一种选择(删除对象)中,如果要删除的对象的静态类型与其动态类型不同,则静态类型应为要删除的对象的动态类型的基类,并且静态类型应具有虚拟析构函数或行为未定义。在第二种选择中删除(数组)如果要删除的对象的动态类型与其静态类型不同,则行为未定义。

虽然这篇文章的意图在我看来只是处理多态性,但结合下面的文章,它可能被解释为,严格地说,你的代码实际上调用了未定义的行为:

[C++11: 3.9.3/1]: ..类型的cv限定或cv非限定版本是不同的类型;..

然而,我有理由相信,这可以被视为标准中的措辞缺陷;其意图对我来说似乎很清楚。

同样,这条规则甚至可能暗示程序不会编译:

[C++11: 12.5.4]: ..如果删除表达式以一元::运算符开头,则在全局范围内查找释放函数的名称。否则,如果删除表达式用于释放其静态类型具有虚拟析构函数的类对象,则释放函数是在动态类型的虚拟析构函数的definition点选择的函数(12.4)。否则,如果delete表达式用于释放类T或其数组的对象,则对象的静态和动态类型应该是相同的删除,并且在T的作用域中查找释放函数的名称。如果此查找失败,则在全局作用域中查找该名称。如果查找的结果不明确或不可访问,或者如果查找选择了一个位置释放函数,则程序是病态的。

但是,这不是规则的目的,它解决了在没有虚拟析构函数的情况下的多态性,以及跨多个类声明的真正的多义性。

总而言之,在解释这些规则的措辞时,您最好的选择仍然是我们开始时的非规范但非常明确的注释。

票数 5
EN

Stack Overflow用户

发布于 2013-04-19 16:13:21

应该不会有任何问题,因为"unsigned char“(或任何数据类型)上的"const"-ness使其成为只读数据。

在delete中使用"[]“指示必须删除一个数组。

要了解"delete“和"delete []”背后的含义,请阅读this

票数 1
EN

Stack Overflow用户

发布于 2013-04-19 17:01:47

首先,您应该避免在c++中使用这种类型的数组,而应该使用std::vector<unsigned char>

关于const关键字。它只是告诉编译器和读取代码的人,这个成员/变量/参数不应该被更改。

使用指针时,const关键字的位置很重要:

(编辑:找到我借用这部分的Greyson的答案)

const关键字将其左侧的部分标记为常量(如果它位于开头,则用于紧随其后的类型,因此const unsigned charunsigned char const相等)

要将指针标记为常量,请执行以下操作(内容仍可更改):

代码语言:javascript
复制
unsigned char * const aConstantPointerToAMutableContent;

要将内容标记为const,请执行以下操作:

代码语言:javascript
复制
const unsigned char * aPointerToAConstantContentA;
unsigned char const * aPointerToAConstantContentB;

要将两者标记为常量,请执行以下操作:

代码语言:javascript
复制
const unsigned char * const aConstantPointerToAConstantContent;

它对编译器和用户都是一个提示,这样就可以清楚地知道对数据做了什么或没有做什么。如果参数为const unsigned char *,那么用户将知道如果传递该内容,该内容将不会被更改。

因为const关键字只是一个标记,如果某些东西是可变的,那么它对大小本身没有影响,所以对于delete,它应该没有影响。(请参阅Lightness Races in Orbit的答案和评论,也可以将"Is const_cast safe?“作为兴趣)。

但是我不喜欢你的代码的是构造函数是公共的。我可以直接调用它,但因为参数是const unsigned char* array,所以我不希望该类更改内容或在销毁时将其删除。(我不期望直接创建对象的行为方式与使用工厂的方式不同。)

因此,我会将工厂方法作为类的static方法,并将构造函数设置为protected

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16100069

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档