Make ConditionedCostFunction compatible with repeated CostFunction.
If the user uses the same conditioner twice, it does not lead
to a double free errors.
https://github.com/ceres-solver/ceres-solver/issues/422
Change-Id: I9041ddcbffa8dcb882a63bddb82b384897efc970
diff --git a/include/ceres/conditioned_cost_function.h b/include/ceres/conditioned_cost_function.h
index e5f5fc4..f92787e 100644
--- a/include/ceres/conditioned_cost_function.h
+++ b/include/ceres/conditioned_cost_function.h
@@ -77,6 +77,8 @@
// per-residual conditioner. Takes ownership of all of the wrapped cost
// functions, or not, depending on the ownership parameter. Conditioners
// may be NULL, in which case the corresponding residual is not modified.
+ //
+ // The conditioners can repeat.
ConditionedCostFunction(CostFunction* wrapped_cost_function,
const std::vector<CostFunction*>& conditioners,
Ownership ownership);
diff --git a/internal/ceres/conditioned_cost_function.cc b/internal/ceres/conditioned_cost_function.cc
index 08899e3..d933ad7 100644
--- a/internal/ceres/conditioned_cost_function.cc
+++ b/internal/ceres/conditioned_cost_function.cc
@@ -68,7 +68,7 @@
ConditionedCostFunction::~ConditionedCostFunction() {
if (ownership_ == TAKE_OWNERSHIP) {
- STLDeleteElements(&conditioners_);
+ STLDeleteUniqueContainerPointers(conditioners_.begin(), conditioners_.end());
} else {
wrapped_cost_function_.release();
}
diff --git a/internal/ceres/conditioned_cost_function_test.cc b/internal/ceres/conditioned_cost_function_test.cc
index 528e0ee..6297451 100644
--- a/internal/ceres/conditioned_cost_function_test.cc
+++ b/internal/ceres/conditioned_cost_function_test.cc
@@ -67,7 +67,7 @@
};
// Tests that ConditionedCostFunction does what it's supposed to.
-TEST(CostFunctionTest, ConditionedCostFunction) {
+TEST(ConditionedCostFunction, NormalOperation) {
double v1[kTestCostFunctionSize], v2[kTestCostFunctionSize],
jac[kTestCostFunctionSize * kTestCostFunctionSize],
result[kTestCostFunctionSize];
@@ -92,17 +92,16 @@
conditioners.push_back(new LinearCostFunction(i + 2, i * 7));
}
- ConditionedCostFunction conditioned_cost_function(difference_cost_function,
- conditioners,
- TAKE_OWNERSHIP);
+ ConditionedCostFunction conditioned_cost_function(
+ difference_cost_function, conditioners, TAKE_OWNERSHIP);
EXPECT_EQ(difference_cost_function->num_residuals(),
conditioned_cost_function.num_residuals());
EXPECT_EQ(difference_cost_function->parameter_block_sizes(),
conditioned_cost_function.parameter_block_sizes());
- double *parameters[1];
+ double* parameters[1];
parameters[0] = v1;
- double *jacs[1];
+ double* jacs[1];
jacs[0] = jac;
conditioned_cost_function.Evaluate(parameters, result, jacs);
@@ -122,5 +121,21 @@
}
}
+TEST(ConditionedCostFunction, SharedConditionersDoNotTriggerDoubleFree) {
+ // Make a cost function that computes x - v2
+ double v2[kTestCostFunctionSize];
+ VectorRef v2_vector(v2, kTestCostFunctionSize, 1);
+ Matrix identity = Matrix::Identity(kTestCostFunctionSize, kTestCostFunctionSize);
+ NormalPrior* difference_cost_function = new NormalPrior(identity, v2_vector);
+ CostFunction* conditioner = new LinearCostFunction(2, 7);
+ std::vector<CostFunction*> conditioners;
+ for (int i = 0; i < kTestCostFunctionSize; i++) {
+ conditioners.push_back(conditioner);
+ }
+
+ ConditionedCostFunction conditioned_cost_function(
+ difference_cost_function, conditioners, TAKE_OWNERSHIP);
+}
+
} // namespace internal
} // namespace ceres