vector<const *T>, vector<*T>

本文探讨了C++中关于vector容器与const安全性的转换问题,解释了为什么不能从vector<T*>隐式转换为vector<const T*>,并给出了具体的代码示例。

Q:

 void f(vector<const T*>& p)
 {
 }
 int main()
 { 
  vector<T*> nonConstVec;
  f(nonConstVec);
 }

The following does not compile.The thing is that vector<T*> can not be converted to vector <const T*> , and that seems illogically to me , because there exists implicit conversion from T* to const T*. Why is this ?

vector<const T*> can not be converted to vector <T*> too, but that is expected because const T* can not be converted implicitly to T*.


A1:

I've added a few lines to your code. That's sufficient to make it clear why this is disallowed:

void f(vector<const T*>& p)
 {
    static const T ct;
    p.push_back(&ct); // adds a const T* to nonConstVec !
 }
 int main()
 { 
  vector<T*> nonConstVec;
  f(nonConstVec);
  nonConstVec.back()->nonConstFunction();
 }


A2:

It may be worth showing why it's a breach of const-correctness to perform the conversion you want:

#include <vector>
const int a = 1;

void addConst(std::vector<const int *> &v) {
    v.push_back(&a); // this is OK, adding a const int* to a vector of same
}

int main() {
    std::vector<int *> w;
    int b = 2;
    w.push_back(&b);  // this is OK, adding an int* to a vector of same
    *(w.back()) = 3;  // this is OK, assigning through an int*
    addConst(w);      // you want this to be OK, but it isn't...
    *(w.back()) = 3;  // ...because it would make this const-unsafe.
}

The problem is that vector<int*>.push_back takes a pointer-to-non-const (which I'll call a "non-const pointer" from now on). That means, it might modify the pointee of its parameter. Specifically in the case of vector, it might hand the pointer back out to someone else who modifies it. So you can't pass a const pointer to the push_back function of w, and the conversion you want is unsafe even if the template system supported it (which it doesn't). The purpose of const-safety is to stop you passing a const pointer to a function which takes a non-const pointer, and this is how it does its job. C++ requires you to specifically say if you want to do something unsafe, so the conversion certainly can't be implicit. In fact, because of how templates work, it's not possible at all (see later).

I think C++ could in principle preserve const-safety by allowing a conversion from vector<T*>& to const vector<const T*>&, just as int ** to const int *const * is safe. But that's because of the way vector is defined: it wouldn't necessarily be const-safe for other templates.

Likewise, it could in theory allow an explicit conversion. And in fact, it does allow an explicit conversion, but only for objects, not references ;-)

std::vector<const int*> x(w.begin(), w.end()); // conversion

The reason it can't do it for references is because the template system can't support it. Another example that would be broken if the conversion were allowed:

template<typename T> 
struct Foo {
    void Bar(T &);
};

template<>
struct Foo<const int *> {
    void Baz(int *);
};

Now, Foo<int*> doesn't have a Baz function. How on earth could a pointer or reference to Foo<int*> be converted to a pointer or reference to Foo<const int*>?

Foo<int *> f;
Foo<const int *> &g = f; // Not allowed, but suppose it was
int a;
g.Baz(&a); // Um. What happens? Calls Baz on the object f?

From:http://stackoverflow.com/questions/2102244/vector-and-const

### std::vector<tag_t> 的正确用法 在 C++ 中,`std::vector` 是一个动态数组容器,提供了灵活的内存管理和元素访问功能。当使用 `std::vector<tag_t>` 时,确保以下几点以实现正确的用法: 1. **定义与初始化** 使用 `std::vector<tag_t>` 时,可以通过多种方式定义和初始化向量。例如: ```cpp #include <vector> typedef struct { int a; float b; } tag_t; std::vector<tag_t> vec; // 定义空向量 vec.push_back({1, 2.0f}); // 添加元素 ``` 2. **迭代器的正确使用** 如果函数形参为 `const std::vector<tag_t>&`,则必须使用 `const_iterator` 而非普通 `iterator`[^1]。否则会导致编译错误。例如: ```cpp void printVector(const std::vector<tag_t>& vec) { for (auto it = vec.cbegin(); it != vec.cend(); ++it) { printf("a: %d, b: %f\n", it->a, it->b); } } ``` 3. **内存管理** `std::vector` 自动管理内存,但在嵌套结构中需要注意深拷贝与浅拷贝问题。如果 `tag_t` 包含指针成员,则需手动实现拷贝构造函数和赋值操作符。 ### tag_t 类型不兼容问题解决方案 当遇到 `Tag_t` 和 `tag_t` 不兼容的问题时,可以采取以下措施: 1. **类型检查与转换** 确保 `Tag_t` 和 `tag_t` 的定义一致。如果两者是相同结构但命名不同,可以通过显式类型转换解决。例如: ```cpp void func(std::vector<tag_t> param) { // 函数实现 } std::vector<Tag_t> real_param = {{1, 2.0f}, {3, 4.0f}}; func(std::vector<tag_t>(real_param.begin(), real_param.end())); // 类型转换 ``` 2. **避免隐式转换** 隐式类型转换可能导致未定义行为。建议在函数声明中明确指定类型,并通过编译器选项(如 `-Wconversion`)检测潜在问题。 3. **联合体(union)的使用** 如果 `Tag_t` 和 `tag_t` 的底层数据布局一致,可以通过联合体统一两种类型。例如: ```cpp union CompatibleType { Tag_t tag_t_instance; tag_t Tag_t_instance; }; ``` 4. **宏定义统一类型** 使用宏定义统一类型名称,避免重复定义导致的冲突。例如: ```cpp #define COMMON_TAG_TYPE Tag_t #define COMMON_TAG_TYPE tag_t ``` 5. **嵌入式系统中的注意事项** 在嵌入式系统中,确保类型转换过程中不会被中断打断。可以通过禁用中断的方式保护关键代码段[^2]。 ### 示例代码 以下是一个完整的示例,展示如何正确使用 `std::vector<tag_t>` 并解决类型不兼容问题: ```cpp #include <vector> #include <cstdio> typedef struct { int a; float b; } Tag_t; typedef struct { int a; float b; } tag_t; void func(std::vector<tag_t> param) { for (const auto& elem : param) { printf("a: %d, b: %f\n", elem.a, elem.b); } } int main() { std::vector<Tag_t> real_param = {{1, 2.0f}, {3, 4.0f}}; func(std::vector<tag_t>(real_param.begin(), real_param.end())); // 类型转换 return 0; } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值