You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++中用char[]位拷贝对象并转回原类型是否为未定义行为?

核心问题:自定义image_t实现是否属于未定义行为?

场景与需求

在大型项目中,我遇到了必须使用按值捕获lambda的特殊场景,且因硬件限制,严格禁止按引用捕获目标数据结构。

我的核心数据结构类似如下:

struct my_data_t
{
    std::vector<double> d_data;
    std::vector<int>    i_data;
};

原本通过引用捕获的lambda可以正常修改数据:

my_data_t data{{1.0, 1.3, 1.9, 9.3}, {1, 4, 3, 5}};

const auto my_lam = [&](const int i, const std::pair<double, int> elem)
{
    data.d_data[i] = elem.first;
    data.i_data[i] = elem.second;
};

my_lam(1, {100.3, 15});

但按值捕获的写法无法修改原数据(修改的是拷贝后的副本),完全不符合需求:

my_data_t data{{1.0, 1.3, 1.9, 9.3}, {1, 4, 3, 5}};

auto my_lam = [=](const int i, const std::pair<double, int> elem) mutable
{
    data.d_data[i] = elem.first;
    data.i_data[i] = elem.second;
};

my_lam(1, {100.3, 15});

当前的视图式解决方案

我目前采用的是模板化的"视图"方案:

template <typename data_t> struct vec_image_t
{
    data_t* raw;
    std::size_t c_size;
    // 索引运算符等实现
};

template <template <typename> container_t = std::vector> struct my_data_t
{
    container_t<double> d_data;
    container_t<int>    i_data;
};

但该方案需要大量样板代码完成my_data_t<std::vector>到my_data_t<vec_image_t>的转换,扩展性极差(存在大量my_data_t变体),且处理const场景时非常棘手。

自定义image_t实现思路

我需要一种不调用拷贝构造/析构函数的方式来"持有"原数据,C++20的std::bit_cast因要求类型平凡可拷贝(std::vector不满足)无法使用,因此实现了自定义的类似转换:

首先是image_t的定义:

template <typename thing_t> struct image_t
{
    constexpr static std::size_t cpy_size = sizeof(thing_t);
    char raw[cpy_size];
    
    thing_t* operator -> ()
    {
        return (thing_t*)(&raw[0]);
    }
    
    thing_t& operator * ()
    {
        return *(thing_t*)(&raw[0]);
    }
    // 对应的const版本...
};

然后是转换函数make_image:

template <typename thing_t>
requires(sizeof(thing_t) == sizeof(image_t<thing_t>))
image_t<thing_t> make_image(thing_t& thing)
{
    image_t<thing_t> output;
    std::memcpy(&output.raw[0], &thing, output.cpy_size);
    return output;
}

该方案在测试中可以正常工作:

my_data_t data{{1.0, 1.3, 1.9, 9.3}, {1, 4, 3, 5}};
auto d_img = make_image(data);
auto my_lam = [=](const int i, const std::pair<double, int> elem) mutable
{
    d_img->d_data[i] = elem.first;
    d_img->i_data[i] = elem.second;
};

my_lam(1, {100.3, 15});

它的优势是能移除大量冗余代码,且image_t<thing_t>的使用语义和thing_t*几乎一致,风险程度我认为和存储迭代器相当。

疑问:是否属于未定义行为?

我担心这个实现是未定义行为,但查阅C++标准的"类型别名"规则:

每当尝试通过AliasedType类型的泛左值读取或修改DynamicType类型对象的存储值时,行为未定义,除非满足以下条件之一:

  • ...
  • AliasedType是char...:这允许将任何对象的对象表示形式作为字节数组检查。

我想确认:这个规则是否能免除我的make_image转换的未定义行为?


内容的提问来源于stack exchange,提问作者wvn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 05:40:53