我有一些旧代码的包装。
class A{
L* impl_; // the legacy object has to be in the heap, could be also unique_ptr
A(A const&) = delete;
L* duplicate(){L* ret; legacy_duplicate(impl_, &L); return ret;}
... // proper resource management here
};
const
。我猜想遵循现代规则:https://herbsutter.com/2013/01/01/video-you-dont-know-const-and-mutable/duplicate
之外,此const
看起来是实现复制构造函数的好方法。因此,我不能直接这样做:class A{
L* impl_; // the legacy object has to be in the heap
A(A const& other) : L{other.duplicate()}{} // error calling a non-const function
L* duplicate(){L* ret; legacy_duplicate(impl_, &ret); return ret;}
};
legacy_duplicate
并不是线程安全的,但是我知道退出时该对象将保持原始状态。作为C函数,该行为仅记录在案,而没有常量性的概念。)class A{
L* impl_;
A(A const& other) : L{const_cast<A&>(other).duplicate()}{} // error calling a non-const function
L* duplicate(){L* ret; legacy_duplicate(impl_, &ret); return ret;}
};
duplicate
const并在所有上下文中都涉及线程安全。 (毕竟,旧版函数并不关心const
,因此编译器甚至不会提示。)class A{
L* impl_;
A(A const& other) : L{other.duplicate()}{}
L* duplicate() const{L* ret; legacy_duplicate(impl_, &ret); return ret;}
};
class A{
L* impl_;
A(A const&) = delete;
A(A& other) : L{other.duplicate()}{}
L* duplicate(){L* ret; legacy_duplicate(impl_, &ret); return ret;}
};
const
。class A{
L* impl_;
A(A const& other) : L{other.duplicate_locked()}{}
L* duplicate(){
L* ret; legacy_duplicate(impl_, &ret); return ret;
}
L* duplicate_locked() const{
std::lock_guard<std::mutex> lk(mut);
L* ret; legacy_duplicate(impl_, &ret); return ret;
}
mutable std::mutex mut;
};
legacy_duplicate
并声明复制构造函数不是线程安全的。 (如果需要,请另外创建一个类型为A_mt
的线程安全versión)class A{
L* impl_;
A(A const& other){legacy_duplicate(other.impl_, &impl_);}
};
void legacy_duplicate(L* in, L** out){
*out = new L{};
char tmp = in[0];
in[0] = tmp;
std::memcpy(*out, in, sizeof *in); return;
}
std::auto_ptr
有一个类似的问题,即使用非const“复制”构造函数。结果是auto_ptr
不能在容器内使用。 https://www.quantstart.com/articles/STL-Containers-and-Auto_ptrs-Why-They-Dont-Mix/
最佳答案
我只是同时包含了选项(4)和(5),但是当您认为对性能而言是必要的时,将显式选择加入线程不安全的行为。
这是一个完整的例子。
#include <cstdlib>
#include <thread>
struct L {
int val;
};
void legacy_duplicate(const L* in, L** out) {
*out = new L{};
std::memcpy(*out, in, sizeof *in);
return;
}
class A {
public:
A(L* l) : impl_{l} {}
A(A const& other) : impl_{other.duplicate_locked()} {}
A copy_unsafe_for_multithreading() { return {duplicate()}; }
L* impl_;
L* duplicate() {
printf("in duplicate\n");
L* ret;
legacy_duplicate(impl_, &ret);
return ret;
}
L* duplicate_locked() const {
std::lock_guard<std::mutex> lk(mut);
printf("in duplicate_locked\n");
L* ret;
legacy_duplicate(impl_, &ret);
return ret;
}
mutable std::mutex mut;
};
int main() {
A a(new L{1});
const A b(new L{2});
A c = a;
A d = b;
A e = a.copy_unsafe_for_multithreading();
A f = const_cast<A&>(b).copy_unsafe_for_multithreading();
printf("\npointers:\na=%p\nb=%p\nc=%p\nc=%p\nd=%p\nf=%p\n\n", a.impl_,
b.impl_, c.impl_, d.impl_, e.impl_, f.impl_);
printf("vals:\na=%d\nb=%d\nc=%d\nc=%d\nd=%d\nf=%d\n", a.impl_->val,
b.impl_->val, c.impl_->val, d.impl_->val, e.impl_->val, f.impl_->val);
}
in duplicate_locked
in duplicate_locked
in duplicate
in duplicate
pointers:
a=0x7f85e8c01840
b=0x7f85e8c01850
c=0x7f85e8c01860
c=0x7f85e8c01870
d=0x7f85e8c01880
f=0x7f85e8c01890
vals:
a=1
b=2
c=1
c=2
d=1
f=2
const
传达线程安全性,但是调用API的代码可以使用const_cast
退出
https://stackoverflow.com/questions/60087792/