投射向量地址以复制数据

时间:2019-07-10 14:27:15

标签: c++ stdvector

我写了一个看起来不错的手术,但是我不能确定它是否真的合法。

我有一个行类和扩展名

class Row {};
class SuperRow : public Row {};

我有一个返回向量的函数

std::vector<Row> GetRows(){
    Row row1;
    Row row2;
    std::vector<Row> rows;
    rows.push_back(row1);
    rows.push_back(row2);
    return rows;
}

我还有一个需要该数据的函数,但是它具有一个对象向量,这些对象扩展了主向量的数据类型。

void GetData(std::vector<SuperRow> *rows){
    // in order to compile, must do this
    *((std::vector<Row>*)rows) = GetRows();
}

这有效,但我正在查看时就好像做错了什么.. [编辑:好的,显然这很糟糕]


我也可能以不同的方式做同样的事情。

void GetRowsOtherWay(std::vector<Row> *rows){
   *rows = GetRows();
}

void GetDataOtherWay(std::vector<SuperRow> *rows){
    GetRowsOtherWay((std::vector<Row>*)rows);
}

这还不好吗?

1 个答案:

答案 0 :(得分:2)

  

但是我不能确定它是否真的合法。

GetDataGetDataOtherWay不是“合法”。该程序的行为是不确定的。

虽然

GetRowsOtherWay本身很好,但是您应该使用引用而不是指针参数。如果确实使用了指针,则可能应该检查它是否不为空。

  

对容器来说,这只是“不好”吗?因为在我们的代码库中的每个地方,我都看到人们将对象ptrs强制转换为其基类,即GetThatRow((Row*)&mySuperRow);

将指针转换为指向base的指针是可以的。但是,派生对象的矢量不是从基础对象的矢量派生的。 Vector根本没有基类。

请注意,那里的演员阵容是多余且冒险的。转换为基本指针是隐式的,因此GetThatRow(&mySuperRow)也可以正常工作。如果要使其明确,请使用static_cast,以便编译器强制执行类型安全。

  

这有效

出现“正常工作”是一个可能的不确定行为的例子。


  

不应该将对象显式转换为基类的对象吗?

不一样。另外,我们在这里讨论指针的转换(尽管也适用于引用),而不是对象的转换。在相同的继承层次结构中,存在从指针类型到另一种指针类型的静态转换。从指向一个向量的指针到指向另一个向量的指针不存在静态转换。这些类型不是通过继承关联的。

  

我们怎么知道这是UB?

因为标准是这样(引自标准草案):

  

[basic.lval]

     

如果程序尝试通过以下方式访问对象的存储值   一种glvalue,其类型与以下一种不相似([conv.qual])   以下类型行为未定义

     
      
  • 对象的动态类型,
  •   
  • 一种类型,它是与对象的动态类型相对应的有符号或无符号类型,或者
  •   
  • char,unsigned char或std :: byte类型。
  •   

std::vector<Row>*rows的动态类型(即std::vector<SuperRow>)相似,也与有符号或无符号的对应类型相似,也与{{1} },charunsigned char

一个好的经验法则:避免重新解释转换,如果需要,请确保您知道所涉及的语言规则,并且没有违反它们。永远不要使用C样式转换,因为无论您是否打算使用C样式转换,它都会重新解释转换。


如何从基础对象的向量创建派生对象的向量:首先,您需要一个从基础对象创建派生对象的函数。尽管可以通过将转换构造函数添加到派生类型来实现,但通常无法将基础对象转换为其派生类型。编写了此类函数后,请使用std::byte将其应用于碱基向量。

将派生向量转换为基向量更简单,因为可以简单地复制并返回基子对象。此操作称为切片。