我知道RVO主要应用但我可以指望吗?我有一个函数创建一个FlagContainer类的对象。
class FlagContainer {
public:
~FlagContainer() {
someItem->flag = true;
}
private:
Item * someItem;
}
public FlagContainer createFlagContainer() {
return FlagContainer();
}
调用者使用容器后,必须设置标志。所以我可以用析构函数来做这个。
{
FlagContainer container = createFlagContainer();
// do something with container
}
当超出范围时,将调用析构函数。但是我可以确定在createFlagContainer中永远不会调用析构函数吗?有没有办法实现这个目标?
我会使用AVR GCC 4.7.0编译器。
答案 0 :(得分:5)
我知道RVO主要应用但我可以指望吗?
不要依赖RVO来获取逻辑。简而言之,编译程序的人可以使用命令行选项将其关闭。
有没有办法实现这个目标?
令人惊讶的是,标准库已经为您提供了这一功能,因此您不需要自己承担实施它的风险(移动构造函数和运算符非常难以正确实现)
带有自定义删除工具的 std::unique_ptr
可以很好地完成工作。
#include <iostream>
#include <memory>
#include <cassert>
// test type
struct X
{
bool flag = false;
};
// a custom deleter that sets a flag on the target
struct flag_setter_impl
{
template<class X>
void operator()(X* px) const {
if (px) {
assert(!px->flag);
std::cout << "setting flag!" << std::endl;
px->flag = true;
}
}
};
// a type of unique_ptr which does not delete, but sets a flag
template<class X>
using flag_setter = std::unique_ptr<X, flag_setter_impl>;
// make a flag_stter for x
template<class X>
auto make_flag_setter(X& x) -> flag_setter<X>
{
return flag_setter<X>(&x, flag_setter_impl());
}
// quick test
auto main() -> int
{
using namespace std;
X x;
{
auto fs1 = make_flag_setter(x);
auto fs2 = move(fs1);
}
return 0;
}
但我的目标不是STL
然后不要忘记你的0,3,5的规则
#include <iostream>
#include <memory>
#include <cassert>
// test type
struct X
{
bool flag = false;
};
// a custom deleter that sets a flag on the target
struct flag_setter_impl
{
template<class X>
void operator()(X* px) const {
if (px) {
assert(!px->flag);
std::cout << "setting flag!" << std::endl;
px->flag = true;
}
}
};
// a type of unique_ptr which does not delete, but sets a flag
template<class X>
struct flag_setter
{
flag_setter(X* px) : px(px) {}
flag_setter(const flag_setter&) = delete;
flag_setter(flag_setter&& r) noexcept : px(r.px) { r.px = nullptr; }
flag_setter& operator=(const flag_setter& r) = delete;
flag_setter& operator=(flag_setter&& r)
{
flag_setter tmp(std::move(r));
std::swap(tmp.px, px);
return *this;
}
~flag_setter() noexcept {
flag_setter_impl()(px);
}
private:
X* px;
};
// make a flag_stter for x
template<class X>
auto make_flag_setter(X& x) -> flag_setter<X>
{
return flag_setter<X>(&x);
}
// quick test
auto main() -> int
{
using namespace std;
X x;
{
auto fs1 = make_flag_setter(x);
auto fs2 = move(fs1);
}
return 0;
}
答案 1 :(得分:2)
无法保证[尚未]应用复制省略。建议将Guaranteed copy-elision纳入C ++ 17。是否应用copy-elision完全由编译器决定(虽然有些编译器可以选择完全禁用它)。
避免这种需求的潜在方法可能是使用一种本质上不可用的类型,它只能用作您感兴趣的类型的构造函数参数并返回该类型的对象:
var timer;
var sliderWrap = $('#sliderUL'),
img = $('#sliderUL img')
singleWidth = sliderWrap.find('img:first-child').width(),
imageLenght = img.length,
idCount = 1,
current = 1,
firstImage = img.first();
lastImage = img.last(),
secondLast = imageLenght-1;
secondImage = img.eq(1);
firstImage.addClass('active');
img.each(function(){
$(this).attr('id','slider_'+idCount++);
});
if(current === 1){
$('#back').addClass('none');
}
$('#next').on('click',nextFun);
$('#back').on('click',backFun);
function backFun(){
clearInterval(timer);
setTimeout(function(){ timer = setInterval(autRotatae,2000);},3000);
if(current === imageLenght){
$('#next').removeClass('none');
}
if(current === 2){
$(this).addClass('none');
}
var backNextSlider = sliderWrap.find('img[id="slider_'+(current-1)+'"]').addClass('active').removeClass('Subactive');
sliderWrap.find('img[id="slider_'+(current)+'"]').removeClass('Subactive').addClass('backActive').removeClass('active');
current--;
}
function nextFun(){
clearInterval(timer);
setTimeout(function(){ timer = setInterval(autRotatae,2000); },3000);
var currentNextSlider = sliderWrap.find('img[id="slider_'+(current+1)+'"]').addClass('active').removeClass('backActive');
sliderWrap.find('img[id="slider_'+(current)+'"]').addClass('Subactive').removeClass('backActive, active');
current++;
if(current === 2){
$('#back').removeClass('none');
}
if(current === imageLenght){
$('#next').addClass('none');
}
}
var mode = 'Next';
function autRotatae(){
if(current == imageLenght)
mode = 'Back';
if(current == 1)
mode = 'Next';
if(mode == 'Next')
{
nextFun();
}
else
backFun();
}
$(document).ready(function(){
timer = setInterval(autRotatae,2000);
})
这样您就可以避免破坏从class FlagContainerBuilder {
friend class FlagContainer;
public:
FlagContainerBuilder(/* suitable arguments go here */);
// nothing goes here
};
class FlagContainer {
// ...
public:
FlagContainer(FlagContainerBuilder&& builder);
// as before
};
FlagContainerBuilder createFlagContainer() { ... }
返回的FlagContainer
。
答案 2 :(得分:1)
我知道RVO主要应用但我可以指望吗?
没有。允许编译器实现RVO,但不是必需的。当你的编译器承诺这样做时,你只能指望它。
答案 3 :(得分:1)
虽然这个特殊情况按照标准12.8 / 3 / p31.1复制和移动类对象[class.copy]呈现为编译器可以执行NRVO(也就是复制省略)的上下文,但你不能依赖它。依赖于这种优化的程序实际上是不可移植的。
为了确保移动对象,我将定义一个移动构造函数,在内部我将使另一个对象的指针为空,而在析构函数中,我将检查指针是否为class FlagContainer {
public:
FlagContainer(FlagContainer&& other) : someItem(other.someItem) {
other.someItem = nullptr;
}
~FlagContainer() {
if(someItem) someItem->flag = true;
}
Item * someItem;
};
FlagContainer createFlagContainer() {
return FlagContainer();
}
,以便将其标志设置为true :
{{1}}